SN06 method related code moved from sony_nc_rfkill_setup to
acpi_callsetfunc_buffer; a new helper sony_call_snc_handle_buffer is
added too, to be used by different handles that need it and not just the
rfkill handles.


Signed-off-by: Marco Chiappero <[email protected]> 
--- 

--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -744,6 +744,72 @@ static int acpi_callsetfunc(acpi_handle 
        return -1;
 }
 
+static int acpi_callsetfunc_buffer(acpi_handle handle, u64 value,
+                                       u8 array[], unsigned int size)
+{
+       u8 buffer[sizeof(value)];
+       int length = -1;
+       struct acpi_object_list params;
+       union acpi_object in_obj;
+       union acpi_object *values;
+       struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+       acpi_status status;
+
+       if (!array || !size)
+               return length;
+
+       /* use a buffer type as parameter to overcome any 32 bits ACPI limit */
+       memcpy(buffer, &value, sizeof(buffer));
+
+       params.count = 1;
+       params.pointer = &in_obj;
+       in_obj.type = ACPI_TYPE_BUFFER;
+       in_obj.buffer.length = sizeof(buffer);
+       in_obj.buffer.pointer = buffer;
+
+       /* since SN06 is the only known method returning a buffer we
+        * can hard code it, it is not necessary to have a parameter
+        */
+       status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
+                       &output);
+       values = (union acpi_object *) output.pointer;
+       if (ACPI_FAILURE(status) || !values) {
+               dprintk("acpi_evaluate_object failed\n");
+               goto error;
+       }
+
+       /* some buggy DSDTs return integer when the output does
+          not execede the 4 bytes size
+       */
+       if (values->type == ACPI_TYPE_BUFFER) {
+               if (values->buffer.length <= 0)
+                       goto error;
+
+               length = size > values->buffer.length ?
+                       values->buffer.length : size;
+
+               memcpy(array, values->buffer.pointer, length);
+       } else if (values->type == ACPI_TYPE_INTEGER) {
+               u32 result = values->integer.value;
+               if (size < 4)
+                       goto error;
+
+               length = 0;
+               while (length != 4) {
+                       array[length] = result & 0xff;
+                       result >>= 8;
+                       length++;
+               }
+       } else {
+               pr_err("Invalid return object 0x%.2x\n", values->type);
+               goto error;
+       }
+
+error:
+       kfree(output.pointer);
+       return length;
+}
+
 struct sony_nc_handles {
        u16 cap[0x10];
        struct device_attribute devattr;
@@ -848,6 +914,24 @@ static int sony_call_snc_handle(unsigned
        return ret;
 }
 
+/* call command method SN06, accepts a wide input buffer, returns a buffer */
+static int sony_call_snc_handle_buffer(unsigned int handle, u64 argument,
+                                       u8 result[], unsigned int size)
+{
+       int ret = 0;
+       int offset = sony_find_snc_handle(handle);
+
+       if (offset < 0)
+               return -1;
+
+       ret = acpi_callsetfunc_buffer(sony_nc_acpi_handle,
+                       offset | argument, result, size);
+       dprintk("called SN06 with 0x%.4llx (%u bytes read)\n",
+                       offset | argument, ret);
+
+       return ret;
+}
+
 /*
  * sony_nc_values input/output validate functions
  */
@@ -1300,21 +1384,17 @@ static void sony_nc_rfkill_update(void)
        }
 }
 
-static void sony_nc_rfkill_setup(struct acpi_device *device)
+static int sony_nc_rfkill_setup(struct acpi_device *device)
 {
+#define        RFKILL_BUFF_SIZE 8
+       u8 dev_code, i, buff[RFKILL_BUFF_SIZE] = { 0 };
        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 };
 
        offset = sony_find_snc_handle(0x124);
        if (offset == -1) {
                offset = sony_find_snc_handle(0x135);
                if (offset == -1)
-                       return;
+                       return 0;
                else
                        sony_rfkill_handle = 0x135;
        } else
@@ -1324,34 +1404,16 @@ static void sony_nc_rfkill_setup(struct 
        /* 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", &params,
-                       &buffer);
-       if (ACPI_FAILURE(status)) {
-               dprintk("Radio device enumeration failed\n");
-               return;
-       }
-
-       device_enum = (union acpi_object *) buffer.pointer;
-       if (!device_enum) {
-               pr_err("No SN06 return object\n");
-               goto out_no_enum;
-       }
-       if (device_enum->type != ACPI_TYPE_BUFFER) {
-               pr_err("Invalid SN06 return object 0x%.2x\n",
-                      device_enum->type);
-               goto out_no_enum;
-       }
+       if (sony_call_snc_handle_buffer(sony_rfkill_handle, 0x000,
+                                       buff, RFKILL_BUFF_SIZE) < 0)
+               return -EIO;
 
        /* 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 < RFKILL_BUFF_SIZE; i++) {
 
-               dev_code = *(device_enum->buffer.pointer + i);
+               dev_code = buff[i];
                if (dev_code == 0xff)
                        break;
 
@@ -1371,9 +1433,7 @@ static void sony_nc_rfkill_setup(struct 
                        sony_nc_setup_rfkill(device, SONY_WIMAX);
        }
 
-out_no_enum:
-       kfree(buffer.pointer);
-       return;
+       return 0;
 }
 
 /* Keyboard backlight feature */


--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" 
in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to