diff options
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 94 |
1 files changed, 71 insertions, 23 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 2896ca4cd9ab..5af53340da6f 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -131,6 +131,7 @@ enum sony_nc_rfkill { | |||
131 | N_SONY_RFKILL, | 131 | N_SONY_RFKILL, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static int sony_rfkill_handle; | ||
134 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; | 135 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
135 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; | 136 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
136 | static void sony_nc_rfkill_update(void); | 137 | static void sony_nc_rfkill_update(void); |
@@ -232,6 +233,7 @@ static int sony_laptop_input_index[] = { | |||
232 | 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ | 233 | 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ |
233 | 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ | 234 | 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ |
234 | -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ | 235 | -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ |
236 | 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */ | ||
235 | }; | 237 | }; |
236 | 238 | ||
237 | static int sony_laptop_input_keycode_map[] = { | 239 | static int sony_laptop_input_keycode_map[] = { |
@@ -293,6 +295,7 @@ static int sony_laptop_input_keycode_map[] = { | |||
293 | KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ | 295 | KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ |
294 | KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ | 296 | KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ |
295 | KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ | 297 | KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ |
298 | KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */ | ||
296 | }; | 299 | }; |
297 | 300 | ||
298 | /* release buttons after a short delay if pressed */ | 301 | /* release buttons after a short delay if pressed */ |
@@ -890,6 +893,8 @@ static struct sony_nc_event sony_100_events[] = { | |||
890 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | 893 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, |
891 | { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, | 894 | { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, |
892 | { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, | 895 | { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, |
896 | { 0xa1, SONYPI_EVENT_MEDIA_PRESSED }, | ||
897 | { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED }, | ||
893 | { 0, 0 }, | 898 | { 0, 0 }, |
894 | }; | 899 | }; |
895 | 900 | ||
@@ -961,7 +966,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) | |||
961 | else | 966 | else |
962 | sony_laptop_report_input_event(ev); | 967 | sony_laptop_report_input_event(ev); |
963 | } | 968 | } |
964 | } else if (sony_find_snc_handle(0x124) == ev) { | 969 | } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) { |
965 | sony_nc_rfkill_update(); | 970 | sony_nc_rfkill_update(); |
966 | return; | 971 | return; |
967 | } | 972 | } |
@@ -1067,7 +1072,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked) | |||
1067 | if (!blocked) | 1072 | if (!blocked) |
1068 | argument |= 0xff0000; | 1073 | argument |= 0xff0000; |
1069 | 1074 | ||
1070 | return sony_call_snc_handle(0x124, argument, &result); | 1075 | return sony_call_snc_handle(sony_rfkill_handle, argument, &result); |
1071 | } | 1076 | } |
1072 | 1077 | ||
1073 | static const struct rfkill_ops sony_rfkill_ops = { | 1078 | static const struct rfkill_ops sony_rfkill_ops = { |
@@ -1110,7 +1115,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, | |||
1110 | if (!rfk) | 1115 | if (!rfk) |
1111 | return -ENOMEM; | 1116 | return -ENOMEM; |
1112 | 1117 | ||
1113 | sony_call_snc_handle(0x124, 0x200, &result); | 1118 | sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); |
1114 | hwblock = !(result & 0x1); | 1119 | hwblock = !(result & 0x1); |
1115 | rfkill_set_hw_state(rfk, hwblock); | 1120 | rfkill_set_hw_state(rfk, hwblock); |
1116 | 1121 | ||
@@ -1129,7 +1134,7 @@ static void sony_nc_rfkill_update() | |||
1129 | int result; | 1134 | int result; |
1130 | bool hwblock; | 1135 | bool hwblock; |
1131 | 1136 | ||
1132 | sony_call_snc_handle(0x124, 0x200, &result); | 1137 | sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); |
1133 | hwblock = !(result & 0x1); | 1138 | hwblock = !(result & 0x1); |
1134 | 1139 | ||
1135 | for (i = 0; i < N_SONY_RFKILL; i++) { | 1140 | for (i = 0; i < N_SONY_RFKILL; i++) { |
@@ -1145,36 +1150,79 @@ static void sony_nc_rfkill_update() | |||
1145 | continue; | 1150 | continue; |
1146 | } | 1151 | } |
1147 | 1152 | ||
1148 | sony_call_snc_handle(0x124, argument, &result); | 1153 | sony_call_snc_handle(sony_rfkill_handle, argument, &result); |
1149 | rfkill_set_states(sony_rfkill_devices[i], | 1154 | rfkill_set_states(sony_rfkill_devices[i], |
1150 | !(result & 0xf), false); | 1155 | !(result & 0xf), false); |
1151 | } | 1156 | } |
1152 | } | 1157 | } |
1153 | 1158 | ||
1154 | static int sony_nc_rfkill_setup(struct acpi_device *device) | 1159 | static void sony_nc_rfkill_setup(struct acpi_device *device) |
1155 | { | 1160 | { |
1156 | int result, ret; | 1161 | int offset; |
1162 | u8 dev_code, i; | ||
1163 | acpi_status status; | ||
1164 | struct acpi_object_list params; | ||
1165 | union acpi_object in_obj; | ||
1166 | union acpi_object *device_enum; | ||
1167 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1157 | 1168 | ||
1158 | if (sony_find_snc_handle(0x124) == -1) | 1169 | offset = sony_find_snc_handle(0x124); |
1159 | return -1; | 1170 | if (offset == -1) { |
1171 | offset = sony_find_snc_handle(0x135); | ||
1172 | if (offset == -1) | ||
1173 | return; | ||
1174 | else | ||
1175 | sony_rfkill_handle = 0x135; | ||
1176 | } else | ||
1177 | sony_rfkill_handle = 0x124; | ||
1178 | dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle); | ||
1160 | 1179 | ||
1161 | ret = sony_call_snc_handle(0x124, 0xb00, &result); | 1180 | /* need to read the whole buffer returned by the acpi call to SN06 |
1162 | if (ret) { | 1181 | * here otherwise we may miss some features |
1163 | printk(KERN_INFO DRV_PFX | 1182 | */ |
1164 | "Unable to enumerate rfkill devices: %x\n", ret); | 1183 | params.count = 1; |
1165 | return ret; | 1184 | params.pointer = &in_obj; |
1185 | in_obj.type = ACPI_TYPE_INTEGER; | ||
1186 | in_obj.integer.value = offset; | ||
1187 | status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, | ||
1188 | &buffer); | ||
1189 | if (ACPI_FAILURE(status)) { | ||
1190 | dprintk("Radio device enumeration failed\n"); | ||
1191 | return; | ||
1192 | } | ||
1193 | |||
1194 | device_enum = (union acpi_object *) buffer.pointer; | ||
1195 | if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) { | ||
1196 | printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n", | ||
1197 | device_enum->type); | ||
1198 | goto out_no_enum; | ||
1166 | } | 1199 | } |
1167 | 1200 | ||
1168 | if (result & 0x1) | 1201 | /* the buffer is filled with magic numbers describing the devices |
1169 | sony_nc_setup_rfkill(device, SONY_WIFI); | 1202 | * available, 0xff terminates the enumeration |
1170 | if (result & 0x2) | 1203 | */ |
1171 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); | 1204 | while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff && |
1172 | if (result & 0x1c) | 1205 | i < device_enum->buffer.length) { |
1173 | sony_nc_setup_rfkill(device, SONY_WWAN); | 1206 | i++; |
1174 | if (result & 0x20) | 1207 | dprintk("Radio devices, looking at 0x%.2x\n", dev_code); |
1175 | sony_nc_setup_rfkill(device, SONY_WIMAX); | ||
1176 | 1208 | ||
1177 | return 0; | 1209 | if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) |
1210 | sony_nc_setup_rfkill(device, SONY_WIFI); | ||
1211 | |||
1212 | if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) | ||
1213 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); | ||
1214 | |||
1215 | if ((0xf0 & dev_code) == 0x20 && | ||
1216 | !sony_rfkill_devices[SONY_WWAN]) | ||
1217 | sony_nc_setup_rfkill(device, SONY_WWAN); | ||
1218 | |||
1219 | if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) | ||
1220 | sony_nc_setup_rfkill(device, SONY_WIMAX); | ||
1221 | } | ||
1222 | |||
1223 | out_no_enum: | ||
1224 | kfree(buffer.pointer); | ||
1225 | return; | ||
1178 | } | 1226 | } |
1179 | 1227 | ||
1180 | static int sony_nc_add(struct acpi_device *device) | 1228 | static int sony_nc_add(struct acpi_device *device) |