aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/asus-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/asus-laptop.c')
-rw-r--r--drivers/platform/x86/asus-laptop.c273
1 files changed, 186 insertions, 87 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b7944f903886..e38f91be0b10 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -81,6 +81,19 @@ static uint wapf = 1;
81module_param(wapf, uint, 0444); 81module_param(wapf, uint, 0444);
82MODULE_PARM_DESC(wapf, "WAPF value"); 82MODULE_PARM_DESC(wapf, "WAPF value");
83 83
84static char *wled_type = "unknown";
85static char *bled_type = "unknown";
86
87module_param(wled_type, charp, 0444);
88MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
89 "(unknown, led or rfkill). "
90 "default is unknown");
91
92module_param(bled_type, charp, 0444);
93MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
94 "(unknown, led or rfkill). "
95 "default is unknown");
96
84static int wlan_status = 1; 97static int wlan_status = 1;
85static int bluetooth_status = 1; 98static int bluetooth_status = 1;
86static int wimax_status = -1; 99static int wimax_status = -1;
@@ -137,6 +150,11 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
137#define WM_RSTS 0x08 /* internal wimax */ 150#define WM_RSTS 0x08 /* internal wimax */
138#define WW_RSTS 0x20 /* internal wwan */ 151#define WW_RSTS 0x20 /* internal wwan */
139 152
153/* WLED and BLED type */
154#define TYPE_UNKNOWN 0
155#define TYPE_LED 1
156#define TYPE_RFKILL 2
157
140/* LED */ 158/* LED */
141#define METHOD_MLED "MLED" 159#define METHOD_MLED "MLED"
142#define METHOD_TLED "TLED" 160#define METHOD_TLED "TLED"
@@ -218,8 +236,9 @@ struct asus_led {
218/* 236/*
219 * Same thing for rfkill 237 * Same thing for rfkill
220 */ 238 */
221struct asus_pega_rfkill { 239struct asus_rfkill {
222 int control_id; /* type of control. Maps to PEGA_* values */ 240 /* type of control. Maps to PEGA_* values or *_RSTS */
241 int control_id;
223 struct rfkill *rfkill; 242 struct rfkill *rfkill;
224 struct asus_laptop *asus; 243 struct asus_laptop *asus;
225}; 244};
@@ -240,6 +259,8 @@ struct asus_laptop {
240 struct key_entry *keymap; 259 struct key_entry *keymap;
241 struct input_polled_dev *pega_accel_poll; 260 struct input_polled_dev *pega_accel_poll;
242 261
262 struct asus_led wled;
263 struct asus_led bled;
243 struct asus_led mled; 264 struct asus_led mled;
244 struct asus_led tled; 265 struct asus_led tled;
245 struct asus_led rled; 266 struct asus_led rled;
@@ -248,6 +269,8 @@ struct asus_laptop {
248 struct asus_led kled; 269 struct asus_led kled;
249 struct workqueue_struct *led_workqueue; 270 struct workqueue_struct *led_workqueue;
250 271
272 int wled_type;
273 int bled_type;
251 int wireless_status; 274 int wireless_status;
252 bool have_rsts; 275 bool have_rsts;
253 bool is_pega_lucid; 276 bool is_pega_lucid;
@@ -256,11 +279,11 @@ struct asus_laptop {
256 int pega_acc_y; 279 int pega_acc_y;
257 int pega_acc_z; 280 int pega_acc_z;
258 281
259 struct rfkill *gps_rfkill; 282 struct asus_rfkill wlan;
260 283 struct asus_rfkill bluetooth;
261 struct asus_pega_rfkill wlanrfk; 284 struct asus_rfkill wwan;
262 struct asus_pega_rfkill btrfk; 285 struct asus_rfkill wimax;
263 struct asus_pega_rfkill wwanrfk; 286 struct asus_rfkill gps;
264 287
265 acpi_handle handle; /* the handle of the hotk device */ 288 acpi_handle handle; /* the handle of the hotk device */
266 u32 ledd_status; /* status of the LED display */ 289 u32 ledd_status; /* status of the LED display */
@@ -274,6 +297,7 @@ static const struct key_entry asus_keymap[] = {
274 {KE_KEY, 0x02, { KEY_SCREENLOCK } }, 297 {KE_KEY, 0x02, { KEY_SCREENLOCK } },
275 {KE_KEY, 0x05, { KEY_WLAN } }, 298 {KE_KEY, 0x05, { KEY_WLAN } },
276 {KE_KEY, 0x08, { KEY_F13 } }, 299 {KE_KEY, 0x08, { KEY_F13 } },
300 {KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
277 {KE_KEY, 0x17, { KEY_ZOOM } }, 301 {KE_KEY, 0x17, { KEY_ZOOM } },
278 {KE_KEY, 0x1f, { KEY_BATTERY } }, 302 {KE_KEY, 0x1f, { KEY_BATTERY } },
279 /* End of Lenovo SL Specific keycodes */ 303 /* End of Lenovo SL Specific keycodes */
@@ -299,6 +323,8 @@ static const struct key_entry asus_keymap[] = {
299 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 323 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
300 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 324 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
301 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ 325 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
326 {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
327 {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
302 {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 328 {KE_KEY, 0x7E, { KEY_BLUETOOTH } },
303 {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 329 {KE_KEY, 0x7D, { KEY_BLUETOOTH } },
304 {KE_KEY, 0x82, { KEY_CAMERA } }, 330 {KE_KEY, 0x82, { KEY_CAMERA } },
@@ -601,6 +627,10 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
601 627
602static void asus_led_exit(struct asus_laptop *asus) 628static void asus_led_exit(struct asus_laptop *asus)
603{ 629{
630 if (!IS_ERR_OR_NULL(asus->wled.led.dev))
631 led_classdev_unregister(&asus->wled.led);
632 if (!IS_ERR_OR_NULL(asus->bled.led.dev))
633 led_classdev_unregister(&asus->bled.led);
604 if (!IS_ERR_OR_NULL(asus->mled.led.dev)) 634 if (!IS_ERR_OR_NULL(asus->mled.led.dev))
605 led_classdev_unregister(&asus->mled.led); 635 led_classdev_unregister(&asus->mled.led);
606 if (!IS_ERR_OR_NULL(asus->tled.led.dev)) 636 if (!IS_ERR_OR_NULL(asus->tled.led.dev))
@@ -642,7 +672,7 @@ static int asus_led_register(struct asus_laptop *asus,
642 672
643static int asus_led_init(struct asus_laptop *asus) 673static int asus_led_init(struct asus_laptop *asus)
644{ 674{
645 int r; 675 int r = 0;
646 676
647 /* 677 /*
648 * The Pegatron Lucid has no physical leds, but all methods are 678 * The Pegatron Lucid has no physical leds, but all methods are
@@ -661,6 +691,16 @@ static int asus_led_init(struct asus_laptop *asus)
661 if (!asus->led_workqueue) 691 if (!asus->led_workqueue)
662 return -ENOMEM; 692 return -ENOMEM;
663 693
694 if (asus->wled_type == TYPE_LED)
695 r = asus_led_register(asus, &asus->wled, "asus::wlan",
696 METHOD_WLAN);
697 if (r)
698 goto error;
699 if (asus->bled_type == TYPE_LED)
700 r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
701 METHOD_BLUETOOTH);
702 if (r)
703 goto error;
664 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED); 704 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
665 if (r) 705 if (r)
666 goto error; 706 goto error;
@@ -963,7 +1003,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
963 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN); 1003 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
964} 1004}
965 1005
966/* 1006/*e
967 * Bluetooth 1007 * Bluetooth
968 */ 1008 */
969static int asus_bluetooth_set(struct asus_laptop *asus, int status) 1009static int asus_bluetooth_set(struct asus_laptop *asus, int status)
@@ -1228,7 +1268,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
1228 ret = asus_gps_switch(asus, !!value); 1268 ret = asus_gps_switch(asus, !!value);
1229 if (ret) 1269 if (ret)
1230 return ret; 1270 return ret;
1231 rfkill_set_sw_state(asus->gps_rfkill, !value); 1271 rfkill_set_sw_state(asus->gps.rfkill, !value);
1232 return rv; 1272 return rv;
1233} 1273}
1234 1274
@@ -1246,90 +1286,139 @@ static const struct rfkill_ops asus_gps_rfkill_ops = {
1246 .set_block = asus_gps_rfkill_set, 1286 .set_block = asus_gps_rfkill_set,
1247}; 1287};
1248 1288
1289static int asus_rfkill_set(void *data, bool blocked)
1290{
1291 struct asus_rfkill *rfk = data;
1292 struct asus_laptop *asus = rfk->asus;
1293
1294 if (rfk->control_id == WL_RSTS)
1295 return asus_wlan_set(asus, !blocked);
1296 else if (rfk->control_id == BT_RSTS)
1297 return asus_bluetooth_set(asus, !blocked);
1298 else if (rfk->control_id == WM_RSTS)
1299 return asus_wimax_set(asus, !blocked);
1300 else if (rfk->control_id == WW_RSTS)
1301 return asus_wwan_set(asus, !blocked);
1302
1303 return -EINVAL;
1304}
1305
1306static const struct rfkill_ops asus_rfkill_ops = {
1307 .set_block = asus_rfkill_set,
1308};
1309
1310static void asus_rfkill_terminate(struct asus_rfkill *rfk)
1311{
1312 if (!rfk->rfkill)
1313 return ;
1314
1315 rfkill_unregister(rfk->rfkill);
1316 rfkill_destroy(rfk->rfkill);
1317 rfk->rfkill = NULL;
1318}
1319
1249static void asus_rfkill_exit(struct asus_laptop *asus) 1320static void asus_rfkill_exit(struct asus_laptop *asus)
1250{ 1321{
1251 if (asus->gps_rfkill) { 1322 asus_rfkill_terminate(&asus->wwan);
1252 rfkill_unregister(asus->gps_rfkill); 1323 asus_rfkill_terminate(&asus->bluetooth);
1253 rfkill_destroy(asus->gps_rfkill); 1324 asus_rfkill_terminate(&asus->wlan);
1254 asus->gps_rfkill = NULL; 1325 asus_rfkill_terminate(&asus->gps);
1255 }
1256} 1326}
1257 1327
1258static int asus_rfkill_init(struct asus_laptop *asus) 1328static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
1329 const char *name, int control_id, int type,
1330 const struct rfkill_ops *ops)
1259{ 1331{
1260 int result; 1332 int result;
1261 1333
1262 if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) || 1334 rfk->control_id = control_id;
1263 acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) || 1335 rfk->asus = asus;
1264 acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) 1336 rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
1265 return 0; 1337 type, ops, rfk);
1266 1338 if (!rfk->rfkill)
1267 asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
1268 RFKILL_TYPE_GPS,
1269 &asus_gps_rfkill_ops, asus);
1270 if (!asus->gps_rfkill)
1271 return -EINVAL; 1339 return -EINVAL;
1272 1340
1273 result = rfkill_register(asus->gps_rfkill); 1341 result = rfkill_register(rfk->rfkill);
1274 if (result) { 1342 if (result) {
1275 rfkill_destroy(asus->gps_rfkill); 1343 rfkill_destroy(rfk->rfkill);
1276 asus->gps_rfkill = NULL; 1344 rfk->rfkill = NULL;
1277 } 1345 }
1278 1346
1279 return result; 1347 return result;
1280} 1348}
1281 1349
1282static int pega_rfkill_set(void *data, bool blocked) 1350static int asus_rfkill_init(struct asus_laptop *asus)
1283{ 1351{
1284 struct asus_pega_rfkill *pega_rfk = data; 1352 int result = 0;
1285 1353
1286 int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked); 1354 if (asus->is_pega_lucid)
1287 pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret); 1355 return -ENODEV;
1288 1356
1289 return ret; 1357 if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
1290} 1358 !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
1359 !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
1360 result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
1361 -1, RFKILL_TYPE_GPS,
1362 &asus_gps_rfkill_ops);
1363 if (result)
1364 goto exit;
1291 1365
1292static const struct rfkill_ops pega_rfkill_ops = {
1293 .set_block = pega_rfkill_set,
1294};
1295 1366
1296static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk) 1367 if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
1297{ 1368 asus->wled_type == TYPE_RFKILL)
1298 pr_warn("Terminating %d\n", pega_rfk->control_id); 1369 result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
1299 if (pega_rfk->rfkill) { 1370 WL_RSTS, RFKILL_TYPE_WLAN,
1300 rfkill_unregister(pega_rfk->rfkill); 1371 &asus_rfkill_ops);
1301 rfkill_destroy(pega_rfk->rfkill); 1372 if (result)
1302 pega_rfk->rfkill = NULL; 1373 goto exit;
1303 }
1304}
1305 1374
1306static void pega_rfkill_exit(struct asus_laptop *asus) 1375 if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
1307{ 1376 asus->bled_type == TYPE_RFKILL)
1308 pega_rfkill_terminate(&asus->wwanrfk); 1377 result = asus_rfkill_setup(asus, &asus->bluetooth,
1309 pega_rfkill_terminate(&asus->btrfk); 1378 "asus-bluetooth", BT_RSTS,
1310 pega_rfkill_terminate(&asus->wlanrfk); 1379 RFKILL_TYPE_BLUETOOTH,
1380 &asus_rfkill_ops);
1381 if (result)
1382 goto exit;
1383
1384 if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
1385 result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
1386 WW_RSTS, RFKILL_TYPE_WWAN,
1387 &asus_rfkill_ops);
1388 if (result)
1389 goto exit;
1390
1391 if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
1392 result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
1393 WM_RSTS, RFKILL_TYPE_WIMAX,
1394 &asus_rfkill_ops);
1395 if (result)
1396 goto exit;
1397
1398exit:
1399 if (result)
1400 asus_rfkill_exit(asus);
1401
1402 return result;
1311} 1403}
1312 1404
1313static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk, 1405static int pega_rfkill_set(void *data, bool blocked)
1314 const char *name, int controlid, int rfkill_type)
1315{ 1406{
1316 int result; 1407 struct asus_rfkill *rfk = data;
1317 1408
1318 pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type); 1409 int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
1319 pega_rfk->control_id = controlid; 1410 return ret;
1320 pega_rfk->asus = asus; 1411}
1321 pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
1322 rfkill_type, &pega_rfkill_ops, pega_rfk);
1323 if (!pega_rfk->rfkill)
1324 return -EINVAL;
1325 1412
1326 result = rfkill_register(pega_rfk->rfkill); 1413static const struct rfkill_ops pega_rfkill_ops = {
1327 if (result) { 1414 .set_block = pega_rfkill_set,
1328 rfkill_destroy(pega_rfk->rfkill); 1415};
1329 pega_rfk->rfkill = NULL;
1330 }
1331 1416
1332 return result; 1417static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
1418 const char *name, int controlid, int rfkill_type)
1419{
1420 return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
1421 &pega_rfkill_ops);
1333} 1422}
1334 1423
1335static int pega_rfkill_init(struct asus_laptop *asus) 1424static int pega_rfkill_init(struct asus_laptop *asus)
@@ -1339,22 +1428,22 @@ static int pega_rfkill_init(struct asus_laptop *asus)
1339 if(!asus->is_pega_lucid) 1428 if(!asus->is_pega_lucid)
1340 return -ENODEV; 1429 return -ENODEV;
1341 1430
1342 ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN); 1431 ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
1343 if(ret) 1432 PEGA_WLAN, RFKILL_TYPE_WLAN);
1344 return ret;
1345 ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
1346 if(ret) 1433 if(ret)
1347 goto err_btrfk; 1434 goto exit;
1348 ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN); 1435
1436 ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
1437 PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
1349 if(ret) 1438 if(ret)
1350 goto err_wwanrfk; 1439 goto exit;
1351 1440
1352 pr_warn("Pega rfkill init succeeded\n"); 1441 ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
1353 return 0; 1442 PEGA_WWAN, RFKILL_TYPE_WWAN);
1354err_wwanrfk: 1443
1355 pega_rfkill_terminate(&asus->btrfk); 1444exit:
1356err_btrfk: 1445 if (ret)
1357 pega_rfkill_terminate(&asus->wlanrfk); 1446 asus_rfkill_exit(asus);
1358 1447
1359 return ret; 1448 return ret;
1360} 1449}
@@ -1364,8 +1453,10 @@ err_btrfk:
1364 */ 1453 */
1365static void asus_input_notify(struct asus_laptop *asus, int event) 1454static void asus_input_notify(struct asus_laptop *asus, int event)
1366{ 1455{
1367 if (asus->inputdev) 1456 if (!asus->inputdev)
1368 sparse_keymap_report_event(asus->inputdev, event, 1, true); 1457 return ;
1458 if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
1459 pr_info("Unknown key %x pressed\n", event);
1369} 1460}
1370 1461
1371static int asus_input_init(struct asus_laptop *asus) 1462static int asus_input_init(struct asus_laptop *asus)
@@ -1375,7 +1466,7 @@ static int asus_input_init(struct asus_laptop *asus)
1375 1466
1376 input = input_allocate_device(); 1467 input = input_allocate_device();
1377 if (!input) { 1468 if (!input) {
1378 pr_info("Unable to allocate input device\n"); 1469 pr_warn("Unable to allocate input device\n");
1379 return -ENOMEM; 1470 return -ENOMEM;
1380 } 1471 }
1381 input->name = "Asus Laptop extra buttons"; 1472 input->name = "Asus Laptop extra buttons";
@@ -1390,7 +1481,7 @@ static int asus_input_init(struct asus_laptop *asus)
1390 } 1481 }
1391 error = input_register_device(input); 1482 error = input_register_device(input);
1392 if (error) { 1483 if (error) {
1393 pr_info("Unable to register input device\n"); 1484 pr_warn("Unable to register input device\n");
1394 goto err_free_keymap; 1485 goto err_free_keymap;
1395 } 1486 }
1396 1487
@@ -1688,7 +1779,16 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1688 if (result) 1779 if (result)
1689 return result; 1780 return result;
1690 1781
1691 /* WLED and BLED are on by default */ 1782 if (!strcmp(bled_type, "led"))
1783 asus->bled_type = TYPE_LED;
1784 else if (!strcmp(bled_type, "rfkill"))
1785 asus->bled_type = TYPE_RFKILL;
1786
1787 if (!strcmp(wled_type, "led"))
1788 asus->wled_type = TYPE_LED;
1789 else if (!strcmp(wled_type, "rfkill"))
1790 asus->wled_type = TYPE_RFKILL;
1791
1692 if (bluetooth_status >= 0) 1792 if (bluetooth_status >= 0)
1693 asus_bluetooth_set(asus, !!bluetooth_status); 1793 asus_bluetooth_set(asus, !!bluetooth_status);
1694 1794
@@ -1786,7 +1886,7 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
1786 goto fail_led; 1886 goto fail_led;
1787 1887
1788 result = asus_rfkill_init(asus); 1888 result = asus_rfkill_init(asus);
1789 if (result) 1889 if (result && result != -ENODEV)
1790 goto fail_rfkill; 1890 goto fail_rfkill;
1791 1891
1792 result = pega_accel_init(asus); 1892 result = pega_accel_init(asus);
@@ -1828,7 +1928,6 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
1828 asus_led_exit(asus); 1928 asus_led_exit(asus);
1829 asus_input_exit(asus); 1929 asus_input_exit(asus);
1830 pega_accel_exit(asus); 1930 pega_accel_exit(asus);
1831 pega_rfkill_exit(asus);
1832 asus_platform_exit(asus); 1931 asus_platform_exit(asus);
1833 1932
1834 kfree(asus->name); 1933 kfree(asus->name);