|
@@ -691,59 +691,92 @@ static struct acpi_device *sony_nc_acpi_device = NULL;
|
|
|
|
|
|
/*
|
|
|
* 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 out_obj;
|
|
|
+ union acpi_object *result = NULL;
|
|
|
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
acpi_status status;
|
|
|
|
|
|
- output.length = sizeof(out_obj);
|
|
|
- output.pointer = &out_obj;
|
|
|
+ if (value) {
|
|
|
+ struct acpi_object_list params;
|
|
|
+ union acpi_object in;
|
|
|
+ in.type = ACPI_TYPE_INTEGER;
|
|
|
+ in.integer.value = *value;
|
|
|
+ params.count = 1;
|
|
|
+ params.pointer = ∈
|
|
|
+ status = acpi_evaluate_object(handle, method, ¶ms, &output);
|
|
|
+ } else
|
|
|
+ status = acpi_evaluate_object(handle, method, NULL, &output);
|
|
|
|
|
|
- status = acpi_evaluate_object(handle, name, NULL, &output);
|
|
|
- if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) {
|
|
|
- *result = out_obj.integer.value;
|
|
|
- return 0;
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ pr_err("Failed to evaluate [%s]\n", method);
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
- 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,
|
|
|
- int *result)
|
|
|
+static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
|
|
|
+ int *result)
|
|
|
{
|
|
|
- struct acpi_object_list params;
|
|
|
- union acpi_object in_obj;
|
|
|
- struct acpi_buffer output;
|
|
|
- union acpi_object out_obj;
|
|
|
- acpi_status status;
|
|
|
-
|
|
|
- params.count = 1;
|
|
|
- params.pointer = &in_obj;
|
|
|
- in_obj.type = ACPI_TYPE_INTEGER;
|
|
|
- in_obj.integer.value = value;
|
|
|
+ union acpi_object *object = NULL;
|
|
|
+ if (value) {
|
|
|
+ u64 v = *value;
|
|
|
+ object = __call_snc_method(handle, name, &v);
|
|
|
+ } else
|
|
|
+ object = __call_snc_method(handle, name, NULL);
|
|
|
|
|
|
- output.length = sizeof(out_obj);
|
|
|
- output.pointer = &out_obj;
|
|
|
+ if (!object)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- status = acpi_evaluate_object(handle, name, ¶ms, &output);
|
|
|
- if (status == AE_OK) {
|
|
|
- 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;
|
|
|
+ if (object->type != ACPI_TYPE_INTEGER) {
|
|
|
+ pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
|
|
|
+ ACPI_TYPE_INTEGER, object->type);
|
|
|
+ kfree(object);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- 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 {
|
|
@@ -770,16 +803,17 @@ static ssize_t sony_nc_handles_show(struct device *dev,
|
|
|
|
|
|
static int sony_nc_handles_setup(struct platform_device *pd)
|
|
|
{
|
|
|
- int i;
|
|
|
- int result;
|
|
|
+ int i, r, result, arg;
|
|
|
|
|
|
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)) {
|
|
|
+ arg = i + 0x20;
|
|
|
+ r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
|
|
|
+ &result);
|
|
|
+ if (!r) {
|
|
|
dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
|
|
|
result, i);
|
|
|
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)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
+ int arg, ret = 0;
|
|
|
int offset = sony_find_snc_handle(handle);
|
|
|
|
|
|
if (offset < 0)
|
|
|
return -1;
|
|
|
|
|
|
- ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
|
|
|
- result);
|
|
|
- dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
|
|
|
- *result);
|
|
|
+ arg = offset | argument;
|
|
|
+ ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
|
|
|
+ dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
|
|
|
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,
|
|
|
char *buffer)
|
|
|
{
|
|
|
- int value;
|
|
|
+ int value, ret = 0;
|
|
|
struct sony_nc_value *item =
|
|
|
container_of(attr, struct sony_nc_value, devattr);
|
|
|
|
|
|
if (!*item->acpiget)
|
|
|
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;
|
|
|
|
|
|
if (item->validate)
|
|
@@ -909,7 +944,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
|
|
|
struct device_attribute *attr,
|
|
|
const char *buffer, size_t count)
|
|
|
{
|
|
|
- int value;
|
|
|
+ int value, ret = 0;
|
|
|
struct sony_nc_value *item =
|
|
|
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)
|
|
|
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;
|
|
|
+
|
|
|
item->value = value;
|
|
|
item->valid = 1;
|
|
|
return count;
|
|
@@ -948,15 +986,15 @@ 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",
|
|
|
- bd->props.brightness + 1, NULL);
|
|
|
+ int arg = bd->props.brightness + 1;
|
|
|
+ return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
|
|
|
}
|
|
|
|
|
|
static int sony_backlight_get_brightness(struct backlight_device *bd)
|
|
|
{
|
|
|
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;
|
|
|
/* brightness levels are 1-based, while backlight ones are 0-based */
|
|
|
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)
|
|
|
{
|
|
|
- int result;
|
|
|
+ int result, arg;
|
|
|
|
|
|
/* 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 */
|
|
|
sony_call_snc_handle(0x0100, 0, &result);
|
|
@@ -1166,8 +1205,8 @@ static int sony_nc_resume(struct acpi_device *device)
|
|
|
|
|
|
if (!item->valid)
|
|
|
continue;
|
|
|
- ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
|
|
|
- item->value, NULL);
|
|
|
+ ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
|
|
|
+ &item->value, NULL);
|
|
|
if (ret < 0) {
|
|
|
pr_err("%s: %d\n", __func__, ret);
|
|
|
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",
|
|
|
&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");
|
|
|
}
|
|
|
|
|
@@ -1314,13 +1354,9 @@ static void sony_nc_rfkill_update(void)
|
|
|
|
|
|
static void sony_nc_rfkill_setup(struct acpi_device *device)
|
|
|
{
|
|
|
- int offset;
|
|
|
- u8 dev_code, i;
|
|
|
- acpi_status status;
|
|
|
- struct acpi_object_list params;
|
|
|
- union acpi_object in_obj;
|
|
|
- union acpi_object *device_enum;
|
|
|
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
+ u64 offset;
|
|
|
+ int i;
|
|
|
+ unsigned char buffer[32] = { 0 };
|
|
|
|
|
|
offset = sony_find_snc_handle(0x124);
|
|
|
if (offset == -1) {
|
|
@@ -1333,59 +1369,34 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
|
|
|
sony_rfkill_handle = 0x124;
|
|
|
dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
|
|
|
|
|
|
- /* need to read the whole buffer returned by the acpi call to SN06
|
|
|
- * here otherwise we may miss some features
|
|
|
- */
|
|
|
- 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", ¶ms,
|
|
|
- &buffer);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- dprintk("Radio device enumeration failed\n");
|
|
|
+ i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
|
|
|
+ 32);
|
|
|
+ if (i < 0)
|
|
|
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
|
|
|
* 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 (dev_code == 0xff)
|
|
|
+ if (buffer[i] == 0xff)
|
|
|
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);
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
- if ((0xf0 & dev_code) == 0x20 &&
|
|
|
+ if ((0xf0 & buffer[i]) == 0x20 &&
|
|
|
!sony_rfkill_devices[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);
|
|
|
}
|
|
|
-
|
|
|
-out_no_enum:
|
|
|
- kfree(buffer.pointer);
|
|
|
- return;
|
|
|
}
|
|
|
|
|
|
/* 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,
|
|
|
struct sony_backlight_props *props)
|
|
|
{
|
|
|
- int offset;
|
|
|
- acpi_status status;
|
|
|
- u8 brlvl, i;
|
|
|
+ u64 offset;
|
|
|
+ int 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 };
|
|
|
+ unsigned char buffer[32] = { 0 };
|
|
|
|
|
|
props->handle = handle;
|
|
|
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
|
|
|
* 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", ¶ms,
|
|
|
- &buffer);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- return;
|
|
|
-
|
|
|
- lvl_enum = (union acpi_object *) buffer.pointer;
|
|
|
- if (!lvl_enum) {
|
|
|
- pr_err("No SN06 return object.");
|
|
|
+ i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
|
|
|
+ 32);
|
|
|
+ if (i < 0)
|
|
|
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.
|
|
|
+ * 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", brlvl);
|
|
|
+ dprintk("Brightness level: %d\n", buffer[i]);
|
|
|
|
|
|
- if (!brlvl)
|
|
|
+ if (!buffer[i])
|
|
|
break;
|
|
|
|
|
|
- if (brlvl > max)
|
|
|
- max = brlvl;
|
|
|
- if (brlvl < min)
|
|
|
- min = brlvl;
|
|
|
+ if (buffer[i] > max)
|
|
|
+ max = buffer[i];
|
|
|
+ if (buffer[i] < min)
|
|
|
+ min = buffer[i];
|
|
|
}
|
|
|
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)
|
|
@@ -1728,7 +1716,8 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
|
|
|
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
|
|
|
&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");
|
|
|
}
|
|
|
|
|
@@ -2684,7 +2673,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
|
|
|
ret = -EIO;
|
|
|
break;
|
|
|
}
|
|
|
- if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
|
|
|
+ if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
|
|
|
+ &value)) {
|
|
|
ret = -EIO;
|
|
|
break;
|
|
|
}
|
|
@@ -2701,8 +2691,9 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
|
|
|
ret = -EFAULT;
|
|
|
break;
|
|
|
}
|
|
|
- if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
|
|
|
- (val8 >> 5) + 1, NULL)) {
|
|
|
+ value = (val8 >> 5) + 1;
|
|
|
+ if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
|
|
|
+ NULL)) {
|
|
|
ret = -EIO;
|
|
|
break;
|
|
|
}
|