aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r--drivers/platform/x86/asus-laptop.c369
1 files changed, 180 insertions, 189 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 74463a07d48b..8834405be1fd 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -201,6 +201,8 @@ ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
201 */ 201 */
202struct asus_hotk { 202struct asus_hotk {
203 char *name; /* laptop name */ 203 char *name; /* laptop name */
204
205 struct platform_device *platform_device;
204 struct acpi_device *device; /* the device we are in */ 206 struct acpi_device *device; /* the device we are in */
205 acpi_handle handle; /* the handle of the hotk device */ 207 acpi_handle handle; /* the handle of the hotk device */
206 char status; /* status of the hotk, for LEDs, ... */ 208 char status; /* status of the hotk, for LEDs, ... */
@@ -222,33 +224,6 @@ static struct acpi_table_header *asus_info;
222/* The actual device the driver binds to */ 224/* The actual device the driver binds to */
223static struct asus_hotk *hotk; 225static struct asus_hotk *hotk;
224 226
225/*
226 * The hotkey driver declaration
227 */
228static const struct acpi_device_id asus_device_ids[] = {
229 {"ATK0100", 0},
230 {"ATK0101", 0},
231 {"", 0},
232};
233MODULE_DEVICE_TABLE(acpi, asus_device_ids);
234
235static int asus_hotk_add(struct acpi_device *device);
236static int asus_hotk_remove(struct acpi_device *device, int type);
237static void asus_hotk_notify(struct acpi_device *device, u32 event);
238
239static struct acpi_driver asus_hotk_driver = {
240 .name = ASUS_HOTK_NAME,
241 .class = ASUS_HOTK_CLASS,
242 .owner = THIS_MODULE,
243 .ids = asus_device_ids,
244 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
245 .ops = {
246 .add = asus_hotk_add,
247 .remove = asus_hotk_remove,
248 .notify = asus_hotk_notify,
249 },
250};
251
252/* The backlight device /sys/class/backlight */ 227/* The backlight device /sys/class/backlight */
253static struct backlight_device *asus_backlight_device; 228static struct backlight_device *asus_backlight_device;
254 229
@@ -936,7 +911,7 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
936 return -EINVAL; 911 return -EINVAL;
937} 912}
938 913
939static void asus_hotk_notify(struct acpi_device *device, u32 event) 914static void asus_acpi_notify(struct acpi_device *device, u32 event)
940{ 915{
941 static struct key_entry *key; 916 static struct key_entry *key;
942 u16 count; 917 u16 count;
@@ -1013,19 +988,49 @@ static struct attribute *asuspf_attributes[] = {
1013 NULL 988 NULL
1014}; 989};
1015 990
1016static struct attribute_group asuspf_attribute_group = { 991static struct attribute_group platform_attribute_group = {
1017 .attrs = asuspf_attributes 992 .attrs = asuspf_attributes
1018}; 993};
1019 994
1020static struct platform_driver asuspf_driver = { 995static int asus_platform_init(void)
996{
997 int result;
998
999 hotk->platform_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
1000 if (!hotk->platform_device)
1001 return -ENOMEM;
1002
1003 result = platform_device_add(hotk->platform_device);
1004 if (result)
1005 goto fail_platform_device;
1006
1007 result = sysfs_create_group(&hotk->platform_device->dev.kobj,
1008 &platform_attribute_group);
1009 if (result)
1010 goto fail_sysfs;
1011 return 0;
1012
1013fail_sysfs:
1014 platform_device_del(hotk->platform_device);
1015fail_platform_device:
1016 platform_device_put(hotk->platform_device);
1017 return result;
1018}
1019
1020static void asus_platform_exit(void)
1021{
1022 sysfs_remove_group(&hotk->platform_device->dev.kobj,
1023 &platform_attribute_group);
1024 platform_device_unregister(hotk->platform_device);
1025}
1026
1027static struct platform_driver platform_driver = {
1021 .driver = { 1028 .driver = {
1022 .name = ASUS_HOTK_FILE, 1029 .name = ASUS_HOTK_FILE,
1023 .owner = THIS_MODULE, 1030 .owner = THIS_MODULE,
1024 } 1031 }
1025}; 1032};
1026 1033
1027static struct platform_device *asuspf_device;
1028
1029static void asus_hotk_add_fs(void) 1034static void asus_hotk_add_fs(void)
1030{ 1035{
1031 ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); 1036 ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
@@ -1196,7 +1201,7 @@ static int asus_hotk_get_info(void)
1196 return AE_OK; 1201 return AE_OK;
1197} 1202}
1198 1203
1199static int asus_input_init(void) 1204static int asus_input_init(struct device *dev)
1200{ 1205{
1201 const struct key_entry *key; 1206 const struct key_entry *key;
1202 int result; 1207 int result;
@@ -1207,6 +1212,7 @@ static int asus_input_init(void)
1207 return 0; 1212 return 0;
1208 } 1213 }
1209 hotk->inputdev->name = "Asus Laptop extra buttons"; 1214 hotk->inputdev->name = "Asus Laptop extra buttons";
1215 hotk->inputdev->dev.parent = dev;
1210 hotk->inputdev->phys = ASUS_HOTK_FILE "/input0"; 1216 hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
1211 hotk->inputdev->id.bustype = BUS_HOST; 1217 hotk->inputdev->id.bustype = BUS_HOST;
1212 hotk->inputdev->getkeycode = asus_getkeycode; 1218 hotk->inputdev->getkeycode = asus_getkeycode;
@@ -1228,101 +1234,6 @@ static int asus_input_init(void)
1228 return result; 1234 return result;
1229} 1235}
1230 1236
1231static int asus_hotk_check(void)
1232{
1233 int result = 0;
1234
1235 result = acpi_bus_get_status(hotk->device);
1236 if (result)
1237 return result;
1238
1239 if (hotk->device->status.present) {
1240 result = asus_hotk_get_info();
1241 } else {
1242 pr_err("Hotkey device not present, aborting\n");
1243 return -EINVAL;
1244 }
1245
1246 return result;
1247}
1248
1249static int asus_hotk_found;
1250
1251static int asus_hotk_add(struct acpi_device *device)
1252{
1253 int result;
1254
1255 pr_notice("Asus Laptop Support version %s\n",
1256 ASUS_LAPTOP_VERSION);
1257
1258 hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
1259 if (!hotk)
1260 return -ENOMEM;
1261
1262 hotk->handle = device->handle;
1263 strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
1264 strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
1265 device->driver_data = hotk;
1266 hotk->device = device;
1267
1268 result = asus_hotk_check();
1269 if (result)
1270 goto end;
1271
1272 asus_hotk_add_fs();
1273
1274 asus_hotk_found = 1;
1275
1276 /* WLED and BLED are on by default */
1277 if (bluetooth_status != -1)
1278 write_status(bt_switch_handle, !!bluetooth_status, BT_ON);
1279 if (wireless_status != -1)
1280 write_status(wl_switch_handle, !!wireless_status, WL_ON);
1281
1282 /* If the h/w switch is off, we need to check the real status */
1283 write_status(NULL, read_status(BT_ON), BT_ON);
1284 write_status(NULL, read_status(WL_ON), WL_ON);
1285
1286 /* LCD Backlight is on by default */
1287 write_status(NULL, 1, LCD_ON);
1288
1289 /* Keyboard Backlight is on by default */
1290 if (kled_set_handle)
1291 set_kled_lvl(1);
1292
1293 /* LED display is off by default */
1294 hotk->ledd_status = 0xFFF;
1295
1296 /* Set initial values of light sensor and level */
1297 hotk->light_switch = 0; /* Default to light sensor disabled */
1298 hotk->light_level = 5; /* level 5 for sensor sensitivity */
1299
1300 if (ls_switch_handle)
1301 set_light_sens_switch(hotk->light_switch);
1302
1303 if (ls_level_handle)
1304 set_light_sens_level(hotk->light_level);
1305
1306 /* GPS is on by default */
1307 write_status(NULL, 1, GPS_ON);
1308
1309end:
1310 if (result) {
1311 kfree(hotk->name);
1312 kfree(hotk);
1313 }
1314
1315 return result;
1316}
1317
1318static int asus_hotk_remove(struct acpi_device *device, int type)
1319{
1320 kfree(hotk->name);
1321 kfree(hotk);
1322
1323 return 0;
1324}
1325
1326static void asus_backlight_exit(void) 1237static void asus_backlight_exit(void)
1327{ 1238{
1328 if (asus_backlight_device) 1239 if (asus_backlight_device)
@@ -1350,18 +1261,6 @@ static void asus_input_exit(void)
1350 input_unregister_device(hotk->inputdev); 1261 input_unregister_device(hotk->inputdev);
1351} 1262}
1352 1263
1353static void __exit asus_laptop_exit(void)
1354{
1355 asus_backlight_exit();
1356 asus_led_exit();
1357 asus_input_exit();
1358
1359 acpi_bus_unregister_driver(&asus_hotk_driver);
1360 sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
1361 platform_device_unregister(asuspf_device);
1362 platform_driver_unregister(&asuspf_driver);
1363}
1364
1365static int asus_backlight_init(struct device *dev) 1264static int asus_backlight_init(struct device *dev)
1366{ 1265{
1367 struct backlight_device *bd; 1266 struct backlight_device *bd;
@@ -1448,87 +1347,179 @@ out:
1448 return rv; 1347 return rv;
1449} 1348}
1450 1349
1451static int __init asus_laptop_init(void) 1350
1351static bool asus_device_present;
1352
1353static int __devinit asus_acpi_init(struct acpi_device *device)
1452{ 1354{
1453 int result; 1355 int result = 0;
1454 1356
1455 result = acpi_bus_register_driver(&asus_hotk_driver); 1357 result = acpi_bus_get_status(hotk->device);
1456 if (result < 0) 1358 if (result)
1457 return result; 1359 return result;
1458 1360 if (!hotk->device->status.present) {
1459 /* 1361 pr_err("Hotkey device not present, aborting\n");
1460 * This is a bit of a kludge. We only want this module loaded
1461 * for ASUS systems, but there's currently no way to probe the
1462 * ACPI namespace for ASUS HIDs. So we just return failure if
1463 * we didn't find one, which will cause the module to be
1464 * unloaded.
1465 */
1466 if (!asus_hotk_found) {
1467 acpi_bus_unregister_driver(&asus_hotk_driver);
1468 return -ENODEV; 1362 return -ENODEV;
1469 } 1363 }
1470 1364
1471 result = asus_input_init(); 1365 result = asus_hotk_get_info();
1472 if (result) 1366 if (result)
1473 goto fail_input; 1367 return result;
1474 1368
1475 /* Register platform stuff */ 1369 asus_hotk_add_fs();
1476 result = platform_driver_register(&asuspf_driver);
1477 if (result)
1478 goto fail_platform_driver;
1479 1370
1480 asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); 1371 /* WLED and BLED are on by default */
1481 if (!asuspf_device) { 1372 write_status(bt_switch_handle, 1, BT_ON);
1482 result = -ENOMEM; 1373 write_status(wl_switch_handle, 1, WL_ON);
1483 goto fail_platform_device1;
1484 }
1485 1374
1486 result = platform_device_add(asuspf_device); 1375 /* If the h/w switch is off, we need to check the real status */
1487 if (result) 1376 write_status(NULL, read_status(BT_ON), BT_ON);
1488 goto fail_platform_device2; 1377 write_status(NULL, read_status(WL_ON), WL_ON);
1378
1379 /* LCD Backlight is on by default */
1380 write_status(NULL, 1, LCD_ON);
1489 1381
1490 result = sysfs_create_group(&asuspf_device->dev.kobj, 1382 /* Keyboard Backlight is on by default */
1491 &asuspf_attribute_group); 1383 if (kled_set_handle)
1384 set_kled_lvl(1);
1385
1386 /* LED display is off by default */
1387 hotk->ledd_status = 0xFFF;
1388
1389 /* Set initial values of light sensor and level */
1390 hotk->light_switch = 0; /* Default to light sensor disabled */
1391 hotk->light_level = 5; /* level 5 for sensor sensitivity */
1392
1393 if (ls_switch_handle)
1394 set_light_sens_switch(hotk->light_switch);
1395
1396 if (ls_level_handle)
1397 set_light_sens_level(hotk->light_level);
1398
1399 /* GPS is on by default */
1400 write_status(NULL, 1, GPS_ON);
1401 return result;
1402}
1403
1404static int __devinit asus_acpi_add(struct acpi_device *device)
1405{
1406 int result;
1407
1408 pr_notice("Asus Laptop Support version %s\n",
1409 ASUS_LAPTOP_VERSION);
1410 hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
1411 if (!hotk)
1412 return -ENOMEM;
1413 hotk->handle = device->handle;
1414 strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
1415 strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
1416 device->driver_data = hotk;
1417 hotk->device = device;
1418
1419 result = asus_acpi_init(device);
1492 if (result) 1420 if (result)
1493 goto fail_sysfs; 1421 goto fail_platform;
1494 1422
1495 result = asus_led_init(&asuspf_device->dev); 1423 /*
1424 * Register the platform device first. It is used as a parent for the
1425 * sub-devices below.
1426 */
1427 result = asus_platform_init();
1496 if (result) 1428 if (result)
1497 goto fail_led; 1429 goto fail_platform;
1498 1430
1499 if (!acpi_video_backlight_support()) { 1431 if (!acpi_video_backlight_support()) {
1500 result = asus_backlight_init(&asuspf_device->dev); 1432 result = asus_backlight_init(&hotk->platform_device->dev);
1501 if (result) 1433 if (result)
1502 goto fail_backlight; 1434 goto fail_backlight;
1503 } else 1435 } else
1504 pr_info("Brightness ignored, must be controlled by " 1436 pr_info("Backlight controlled by ACPI video driver\n");
1505 "ACPI video driver\n");
1506 1437
1438 result = asus_input_init(&hotk->platform_device->dev);
1439 if (result)
1440 goto fail_input;
1441
1442 result = asus_led_init(&hotk->platform_device->dev);
1443 if (result)
1444 goto fail_led;
1445
1446 asus_device_present = true;
1507 return 0; 1447 return 0;
1508 1448
1449fail_led:
1450 asus_input_exit();
1451fail_input:
1452 asus_backlight_exit();
1509fail_backlight: 1453fail_backlight:
1510 asus_led_exit(); 1454 asus_platform_exit();
1455fail_platform:
1456 kfree(hotk->name);
1457 kfree(hotk);
1511 1458
1512fail_led: 1459 return result;
1513 sysfs_remove_group(&asuspf_device->dev.kobj, 1460}
1514 &asuspf_attribute_group);
1515 1461
1516fail_sysfs: 1462static int asus_acpi_remove(struct acpi_device *device, int type)
1517 platform_device_del(asuspf_device); 1463{
1464 asus_backlight_exit();
1465 asus_led_exit();
1466 asus_input_exit();
1467 asus_platform_exit();
1468
1469 kfree(hotk->name);
1470 kfree(hotk);
1471 return 0;
1472}
1473
1474static const struct acpi_device_id asus_device_ids[] = {
1475 {"ATK0100", 0},
1476 {"ATK0101", 0},
1477 {"", 0},
1478};
1479MODULE_DEVICE_TABLE(acpi, asus_device_ids);
1518 1480
1519fail_platform_device2: 1481static struct acpi_driver asus_acpi_driver = {
1520 platform_device_put(asuspf_device); 1482 .name = ASUS_HOTK_NAME,
1483 .class = ASUS_HOTK_CLASS,
1484 .owner = THIS_MODULE,
1485 .ids = asus_device_ids,
1486 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1487 .ops = {
1488 .add = asus_acpi_add,
1489 .remove = asus_acpi_remove,
1490 .notify = asus_acpi_notify,
1491 },
1492};
1521 1493
1522fail_platform_device1: 1494static int __init asus_laptop_init(void)
1523 platform_driver_unregister(&asuspf_driver); 1495{
1496 int result;
1524 1497
1525fail_platform_driver: 1498 result = platform_driver_register(&platform_driver);
1526 asus_input_exit(); 1499 if (result < 0)
1500 return result;
1527 1501
1528fail_input: 1502 result = acpi_bus_register_driver(&asus_acpi_driver);
1503 if (result < 0)
1504 goto fail_acpi_driver;
1505 if (!asus_device_present) {
1506 result = -ENODEV;
1507 goto fail_no_device;
1508 }
1509 return 0;
1529 1510
1511fail_no_device:
1512 acpi_bus_unregister_driver(&asus_acpi_driver);
1513fail_acpi_driver:
1514 platform_driver_unregister(&platform_driver);
1530 return result; 1515 return result;
1531} 1516}
1532 1517
1518static void __exit asus_laptop_exit(void)
1519{
1520 acpi_bus_unregister_driver(&asus_acpi_driver);
1521 platform_driver_unregister(&platform_driver);
1522}
1523
1533module_init(asus_laptop_init); 1524module_init(asus_laptop_init);
1534module_exit(asus_laptop_exit); 1525module_exit(asus_laptop_exit);