aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMarco Chiappero <marco@absence.it>2012-05-19 09:35:48 -0400
committerMatthew Garrett <mjg@redhat.com>2012-05-31 14:29:34 -0400
commit5fe801a7427cb13c530af59e2b77b30d789d9b9a (patch)
tree61d08ee7a9960c266eb10e223084ea9bf873346a /drivers/platform
parent9e1233792933bc9b64133c3b00f2f4ef8b02d1a2 (diff)
sony-laptop: improve SNC initialization and acpi notify callback code
Loop through the list of SNC handles and run the proper initialization function for each of the known handles. Also return void in function where we are not checking the return value anyway. For notifications we also know which handle is linked to the event and the code becomes simpler to read with a switch rather than using convoluted ifs. [malattia@linux.it: Code reworked to merge the initialization code improvements and the notify callback changes. Modified the code paths to allow easier error exit paths. Also fixed some missing break statements and spelling mistakes.] Signed-off-by: Marco Chiappero <marco@absence.it> Signed-off-by: Mattia Dongili <malattia@linux.it> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/sony-laptop.c319
1 files changed, 233 insertions, 86 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index d6c53c622b6c..4420353cfb68 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -141,6 +141,8 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
141 "(default: 0)"); 141 "(default: 0)");
142 142
143static void sony_nc_kbd_backlight_resume(void); 143static void sony_nc_kbd_backlight_resume(void);
144static void sony_nc_kbd_backlight_setup(struct platform_device *pd);
145static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
144 146
145enum sony_nc_rfkill { 147enum sony_nc_rfkill {
146 SONY_WIFI, 148 SONY_WIFI,
@@ -153,6 +155,8 @@ enum sony_nc_rfkill {
153static int sony_rfkill_handle; 155static int sony_rfkill_handle;
154static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; 156static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
155static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; 157static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
158static void sony_nc_rfkill_setup(struct acpi_device *device);
159static void sony_nc_rfkill_cleanup(void);
156static void sony_nc_rfkill_update(void); 160static void sony_nc_rfkill_update(void);
157 161
158/*********** Input Devices ***********/ 162/*********** Input Devices ***********/
@@ -1103,63 +1107,116 @@ static struct sony_nc_event sony_127_events[] = {
1103 { 0, 0 }, 1107 { 0, 0 },
1104}; 1108};
1105 1109
1110static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
1111{
1112 int ret = -EINVAL;
1113 unsigned int result = 0;
1114 struct sony_nc_event *key_event;
1115
1116 if (sony_call_snc_handle(handle, 0x200, &result)) {
1117 dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle,
1118 event);
1119 return -EINVAL;
1120 }
1121
1122 result &= 0xFF;
1123
1124 if (handle == 0x0100)
1125 key_event = sony_100_events;
1126 else
1127 key_event = sony_127_events;
1128
1129 for (; key_event->data; key_event++) {
1130 if (key_event->data == result) {
1131 ret = key_event->event;
1132 break;
1133 }
1134 }
1135
1136 if (!key_event->data)
1137 pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n",
1138 event, result, handle);
1139
1140 return ret;
1141}
1142
1106/* 1143/*
1107 * ACPI callbacks 1144 * ACPI callbacks
1108 */ 1145 */
1109static void sony_nc_notify(struct acpi_device *device, u32 event) 1146static void sony_nc_notify(struct acpi_device *device, u32 event)
1110{ 1147{
1111 u32 ev = event; 1148 u32 real_ev = event;
1149 u8 ev_type = 0;
1150 dprintk("sony_nc_notify, event: 0x%.2x\n", event);
1112 1151
1113 if (ev >= 0x90) { 1152 if (event >= 0x90) {
1114 /* New-style event */ 1153 unsigned int result = 0;
1115 int result; 1154 unsigned int arg = 0;
1116 int key_handle = 0; 1155 unsigned int handle = 0;
1117 ev -= 0x90; 1156 unsigned int offset = event - 0x90;
1118
1119 if (sony_find_snc_handle(0x100) == ev)
1120 key_handle = 0x100;
1121 if (sony_find_snc_handle(0x127) == ev)
1122 key_handle = 0x127;
1123
1124 if (key_handle) {
1125 struct sony_nc_event *key_event;
1126
1127 if (sony_call_snc_handle(key_handle, 0x200, &result)) {
1128 dprintk("sony_nc_notify, unable to decode"
1129 " event 0x%.2x 0x%.2x\n", key_handle,
1130 ev);
1131 /* restore the original event */
1132 ev = event;
1133 } else {
1134 ev = result & 0xFF;
1135
1136 if (key_handle == 0x100)
1137 key_event = sony_100_events;
1138 else
1139 key_event = sony_127_events;
1140
1141 for (; key_event->data; key_event++) {
1142 if (key_event->data == ev) {
1143 ev = key_event->event;
1144 break;
1145 }
1146 }
1147 1157
1148 if (!key_event->data) 1158 if (offset >= ARRAY_SIZE(handles->cap)) {
1149 pr_info("Unknown event: 0x%x 0x%x\n", 1159 pr_err("Event 0x%x outside of capabilities list\n",
1150 key_handle, ev); 1160 event);
1151 else
1152 sony_laptop_report_input_event(ev);
1153 }
1154 } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
1155 sony_nc_rfkill_update();
1156 return; 1161 return;
1157 } 1162 }
1158 } else 1163 handle = handles->cap[offset];
1159 sony_laptop_report_input_event(ev); 1164
1165 /* list of handles known for generating events */
1166 switch (handle) {
1167 /* hotkey event */
1168 case 0x0100:
1169 case 0x0127:
1170 ev_type = 1;
1171 real_ev = sony_nc_hotkeys_decode(event, handle);
1172
1173 if (real_ev > 0)
1174 sony_laptop_report_input_event(real_ev);
1175 else
1176 /* restore the original event for reporting */
1177 real_ev = event;
1178
1179 break;
1180
1181 /* wlan switch */
1182 case 0x0124:
1183 case 0x0135:
1184 /* events on this handle are reported when the
1185 * switch changes position or for battery
1186 * events. We'll notify both of them but only
1187 * update the rfkill device status when the
1188 * switch is moved.
1189 */
1190 ev_type = 2;
1191 sony_call_snc_handle(handle, 0x0100, &result);
1192 real_ev = result & 0x03;
1193
1194 /* hw switch event */
1195 if (real_ev == 1)
1196 sony_nc_rfkill_update();
1197
1198 break;
1199
1200 default:
1201 dprintk("Unknown event 0x%x for handle 0x%x\n",
1202 event, handle);
1203 break;
1204 }
1160 1205
1161 dprintk("sony_nc_notify, event: 0x%.2x\n", ev); 1206 /* clear the event (and the event reason when present) */
1162 acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); 1207 arg = 1 << offset;
1208 sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result);
1209
1210 } else {
1211 /* old style event */
1212 ev_type = 1;
1213 sony_laptop_report_input_event(real_ev);
1214 }
1215
1216 acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev);
1217
1218 acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
1219 dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
1163} 1220}
1164 1221
1165static acpi_status sony_walk_callback(acpi_handle handle, u32 level, 1222static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -1180,21 +1237,126 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
1180/* 1237/*
1181 * ACPI device 1238 * ACPI device
1182 */ 1239 */
1183static int sony_nc_function_setup(struct acpi_device *device) 1240static void sony_nc_function_setup(struct acpi_device *device,
1241 struct platform_device *pf_device)
1184{ 1242{
1185 int result, arg; 1243 unsigned int i, result, bitmask, arg;
1244
1245 if (!handles)
1246 return;
1247
1248 /* setup found handles here */
1249 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1250 unsigned int handle = handles->cap[i];
1251
1252 if (!handle)
1253 continue;
1254
1255 dprintk("setting up handle 0x%.4x\n", handle);
1256
1257 switch (handle) {
1258 case 0x0100:
1259 case 0x0101:
1260 case 0x0127:
1261 /* setup hotkeys */
1262 sony_call_snc_handle(handle, 0, &result);
1263 break;
1264 case 0x0102:
1265 /* setup hotkeys */
1266 sony_call_snc_handle(handle, 0x100, &result);
1267 break;
1268 case 0x0124:
1269 case 0x0135:
1270 sony_nc_rfkill_setup(device);
1271 break;
1272 case 0x0137:
1273 sony_nc_kbd_backlight_setup(pf_device);
1274 break;
1275 default:
1276 continue;
1277 }
1278 }
1186 1279
1187 /* Enable all events */ 1280 /* Enable all events */
1188 arg = 0xffff; 1281 arg = 0x10;
1189 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &arg, &result); 1282 if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1283 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1284 &result);
1285}
1286
1287static void sony_nc_function_cleanup(struct platform_device *pd)
1288{
1289 unsigned int i, result, bitmask, handle;
1190 1290
1191 /* Setup hotkeys */ 1291 /* get enabled events and disable them */
1192 sony_call_snc_handle(0x0100, 0, &result); 1292 sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask);
1193 sony_call_snc_handle(0x0101, 0, &result); 1293 sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result);
1194 sony_call_snc_handle(0x0102, 0x100, &result);
1195 sony_call_snc_handle(0x0127, 0, &result);
1196 1294
1197 return 0; 1295 /* cleanup handles here */
1296 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1297
1298 handle = handles->cap[i];
1299
1300 if (!handle)
1301 continue;
1302
1303 switch (handle) {
1304 case 0x0124:
1305 case 0x0135:
1306 sony_nc_rfkill_cleanup();
1307 break;
1308 case 0x0137:
1309 sony_nc_kbd_backlight_cleanup(pd);
1310 break;
1311 default:
1312 continue;
1313 }
1314 }
1315
1316 /* finally cleanup the handles list */
1317 sony_nc_handles_cleanup(pd);
1318}
1319
1320static void sony_nc_function_resume(void)
1321{
1322 unsigned int i, result, bitmask, arg;
1323
1324 dprintk("Resuming SNC device\n");
1325
1326 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1327 unsigned int handle = handles->cap[i];
1328
1329 if (!handle)
1330 continue;
1331
1332 switch (handle) {
1333 case 0x0100:
1334 case 0x0101:
1335 case 0x0127:
1336 /* re-enable hotkeys */
1337 sony_call_snc_handle(handle, 0, &result);
1338 break;
1339 case 0x0102:
1340 /* re-enable hotkeys */
1341 sony_call_snc_handle(handle, 0x100, &result);
1342 break;
1343 case 0x0124:
1344 case 0x0135:
1345 sony_nc_rfkill_update();
1346 break;
1347 case 0x0137:
1348 sony_nc_kbd_backlight_resume();
1349 break;
1350 default:
1351 continue;
1352 }
1353 }
1354
1355 /* Enable all events */
1356 arg = 0x10;
1357 if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1358 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1359 &result);
1198} 1360}
1199 1361
1200static int sony_nc_resume(struct acpi_device *device) 1362static int sony_nc_resume(struct acpi_device *device)
@@ -1223,16 +1385,8 @@ static int sony_nc_resume(struct acpi_device *device)
1223 } 1385 }
1224 1386
1225 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1387 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1226 &handle))) { 1388 &handle)))
1227 dprintk("Doing SNC setup\n"); 1389 sony_nc_function_resume();
1228 sony_nc_function_setup(device);
1229 }
1230
1231 /* re-read rfkill state */
1232 sony_nc_rfkill_update();
1233
1234 /* restore kbd backlight states */
1235 sony_nc_kbd_backlight_resume();
1236 1390
1237 return 0; 1391 return 0;
1238} 1392}
@@ -1509,18 +1663,18 @@ static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1509 return count; 1663 return count;
1510} 1664}
1511 1665
1512static int sony_nc_kbd_backlight_setup(struct platform_device *pd) 1666static void sony_nc_kbd_backlight_setup(struct platform_device *pd)
1513{ 1667{
1514 int result; 1668 int result;
1515 1669
1516 if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) 1670 if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
1517 return 0; 1671 return;
1518 if (!(result & 0x02)) 1672 if (!(result & 0x02))
1519 return 0; 1673 return;
1520 1674
1521 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); 1675 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
1522 if (!kbdbl_handle) 1676 if (!kbdbl_handle)
1523 return -ENOMEM; 1677 return;
1524 1678
1525 sysfs_attr_init(&kbdbl_handle->mode_attr.attr); 1679 sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
1526 kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; 1680 kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
@@ -1543,14 +1697,14 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1543 __sony_nc_kbd_backlight_mode_set(kbd_backlight); 1697 __sony_nc_kbd_backlight_mode_set(kbd_backlight);
1544 __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout); 1698 __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
1545 1699
1546 return 0; 1700 return;
1547 1701
1548outmode: 1702outmode:
1549 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1703 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1550outkzalloc: 1704outkzalloc:
1551 kfree(kbdbl_handle); 1705 kfree(kbdbl_handle);
1552 kbdbl_handle = NULL; 1706 kbdbl_handle = NULL;
1553 return -1; 1707 return;
1554} 1708}
1555 1709
1556static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) 1710static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
@@ -1726,21 +1880,17 @@ static int sony_nc_add(struct acpi_device *device)
1726 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1880 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1727 &handle))) { 1881 &handle))) {
1728 dprintk("Doing SNC setup\n"); 1882 dprintk("Doing SNC setup\n");
1883 /* retrieve the available handles */
1729 result = sony_nc_handles_setup(sony_pf_device); 1884 result = sony_nc_handles_setup(sony_pf_device);
1730 if (result) 1885 if (!result)
1731 goto outpresent; 1886 sony_nc_function_setup(device, sony_pf_device);
1732 result = sony_nc_kbd_backlight_setup(sony_pf_device);
1733 if (result)
1734 goto outsnc;
1735 sony_nc_function_setup(device);
1736 sony_nc_rfkill_setup(device);
1737 } 1887 }
1738 1888
1739 /* setup input devices and helper fifo */ 1889 /* setup input devices and helper fifo */
1740 result = sony_laptop_setup_input(device); 1890 result = sony_laptop_setup_input(device);
1741 if (result) { 1891 if (result) {
1742 pr_err("Unable to create input devices\n"); 1892 pr_err("Unable to create input devices\n");
1743 goto outkbdbacklight; 1893 goto outsnc;
1744 } 1894 }
1745 1895
1746 if (acpi_video_backlight_support()) { 1896 if (acpi_video_backlight_support()) {
@@ -1798,10 +1948,8 @@ static int sony_nc_add(struct acpi_device *device)
1798 1948
1799 sony_laptop_remove_input(); 1949 sony_laptop_remove_input();
1800 1950
1801 outkbdbacklight:
1802 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1803
1804 outsnc: 1951 outsnc:
1952 sony_nc_function_cleanup(sony_pf_device);
1805 sony_nc_handles_cleanup(sony_pf_device); 1953 sony_nc_handles_cleanup(sony_pf_device);
1806 1954
1807 outpresent: 1955 outpresent:
@@ -1824,11 +1972,10 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1824 device_remove_file(&sony_pf_device->dev, &item->devattr); 1972 device_remove_file(&sony_pf_device->dev, &item->devattr);
1825 } 1973 }
1826 1974
1827 sony_nc_kbd_backlight_cleanup(sony_pf_device); 1975 sony_nc_function_cleanup(sony_pf_device);
1828 sony_nc_handles_cleanup(sony_pf_device); 1976 sony_nc_handles_cleanup(sony_pf_device);
1829 sony_pf_remove(); 1977 sony_pf_remove();
1830 sony_laptop_remove_input(); 1978 sony_laptop_remove_input();
1831 sony_nc_rfkill_cleanup();
1832 dprintk(SONY_NC_DRIVER_NAME " removed.\n"); 1979 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
1833 1980
1834 return 0; 1981 return 0;