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.c149
1 files changed, 116 insertions, 33 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index db32d0337a7..e416867c072 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"
@@ -219,7 +237,8 @@ struct asus_led {
219 * Same thing for rfkill 237 * Same thing for rfkill
220 */ 238 */
221struct asus_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;
@@ -600,6 +623,10 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
600 623
601static void asus_led_exit(struct asus_laptop *asus) 624static void asus_led_exit(struct asus_laptop *asus)
602{ 625{
626 if (!IS_ERR_OR_NULL(asus->wled.led.dev))
627 led_classdev_unregister(&asus->wled.led);
628 if (!IS_ERR_OR_NULL(asus->bled.led.dev))
629 led_classdev_unregister(&asus->bled.led);
603 if (!IS_ERR_OR_NULL(asus->mled.led.dev)) 630 if (!IS_ERR_OR_NULL(asus->mled.led.dev))
604 led_classdev_unregister(&asus->mled.led); 631 led_classdev_unregister(&asus->mled.led);
605 if (!IS_ERR_OR_NULL(asus->tled.led.dev)) 632 if (!IS_ERR_OR_NULL(asus->tled.led.dev))
@@ -641,7 +668,7 @@ static int asus_led_register(struct asus_laptop *asus,
641 668
642static int asus_led_init(struct asus_laptop *asus) 669static int asus_led_init(struct asus_laptop *asus)
643{ 670{
644 int r; 671 int r = 0;
645 672
646 /* 673 /*
647 * The Pegatron Lucid has no physical leds, but all methods are 674 * The Pegatron Lucid has no physical leds, but all methods are
@@ -660,6 +687,16 @@ static int asus_led_init(struct asus_laptop *asus)
660 if (!asus->led_workqueue) 687 if (!asus->led_workqueue)
661 return -ENOMEM; 688 return -ENOMEM;
662 689
690 if (asus->wled_type == TYPE_LED)
691 r = asus_led_register(asus, &asus->wled, "asus::wlan",
692 METHOD_WLAN);
693 if (r)
694 goto error;
695 if (asus->bled_type == TYPE_LED)
696 r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
697 METHOD_BLUETOOTH);
698 if (r)
699 goto error;
663 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED); 700 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
664 if (r) 701 if (r)
665 goto error; 702 goto error;
@@ -962,7 +999,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
962 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN); 999 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
963} 1000}
964 1001
965/* 1002/*e
966 * Bluetooth 1003 * Bluetooth
967 */ 1004 */
968static int asus_bluetooth_set(struct asus_laptop *asus, int status) 1005static int asus_bluetooth_set(struct asus_laptop *asus, int status)
@@ -1245,6 +1282,23 @@ static const struct rfkill_ops asus_gps_rfkill_ops = {
1245 .set_block = asus_gps_rfkill_set, 1282 .set_block = asus_gps_rfkill_set,
1246}; 1283};
1247 1284
1285static int asus_rfkill_set(void *data, bool blocked)
1286{
1287 struct asus_rfkill *rfk = data;
1288 struct asus_laptop *asus = rfk->asus;
1289
1290 if (rfk->control_id == WL_RSTS)
1291 return asus_wlan_set(asus, !blocked);
1292 else if (rfk->control_id == BT_RSTS)
1293 return asus_bluetooth_set(asus, !blocked);
1294
1295 return -EINVAL;
1296}
1297
1298static const struct rfkill_ops asus_rfkill_ops = {
1299 .set_block = asus_rfkill_set,
1300};
1301
1248static void asus_rfkill_terminate(struct asus_rfkill *rfk) 1302static void asus_rfkill_terminate(struct asus_rfkill *rfk)
1249{ 1303{
1250 if (!rfk->rfkill) 1304 if (!rfk->rfkill)
@@ -1263,30 +1317,64 @@ static void asus_rfkill_exit(struct asus_laptop *asus)
1263 asus_rfkill_terminate(&asus->gps); 1317 asus_rfkill_terminate(&asus->gps);
1264} 1318}
1265 1319
1266static int asus_rfkill_init(struct asus_laptop *asus) 1320static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
1321 const char *name, int control_id, int type,
1322 const struct rfkill_ops *ops)
1267{ 1323{
1268 int result; 1324 int result;
1269 1325
1270 if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) || 1326 rfk->control_id = control_id;
1271 acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) || 1327 rfk->asus = asus;
1272 acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) 1328 rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
1273 return 0; 1329 type, ops, rfk);
1274 1330 if (!rfk->rfkill)
1275 asus->gps.rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
1276 RFKILL_TYPE_GPS,
1277 &asus_gps_rfkill_ops, asus);
1278 if (!asus->gps.rfkill)
1279 return -EINVAL; 1331 return -EINVAL;
1280 1332
1281 result = rfkill_register(asus->gps.rfkill); 1333 result = rfkill_register(rfk->rfkill);
1282 if (result) { 1334 if (result) {
1283 rfkill_destroy(asus->gps.rfkill); 1335 rfkill_destroy(rfk->rfkill);
1284 asus->gps.rfkill = NULL; 1336 rfk->rfkill = NULL;
1285 } 1337 }
1286 1338
1287 return result; 1339 return result;
1288} 1340}
1289 1341
1342static int asus_rfkill_init(struct asus_laptop *asus)
1343{
1344 int result = 0;
1345
1346 if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
1347 !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
1348 !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
1349 result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
1350 -1, RFKILL_TYPE_GPS,
1351 &asus_gps_rfkill_ops);
1352 if (result)
1353 goto exit;
1354
1355
1356 if (asus->wled_type == TYPE_RFKILL)
1357 result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
1358 WL_RSTS, RFKILL_TYPE_WLAN,
1359 &asus_rfkill_ops);
1360 if (result)
1361 goto exit;
1362
1363 if (asus->bled_type == TYPE_RFKILL)
1364 result = asus_rfkill_setup(asus, &asus->bluetooth,
1365 "asus-bluetooth", BT_RSTS,
1366 RFKILL_TYPE_BLUETOOTH,
1367 &asus_rfkill_ops);
1368 if (result)
1369 goto exit;
1370
1371exit:
1372 if (result)
1373 asus_rfkill_exit(asus);
1374
1375 return result;
1376}
1377
1290static int pega_rfkill_set(void *data, bool blocked) 1378static int pega_rfkill_set(void *data, bool blocked)
1291{ 1379{
1292 struct asus_rfkill *rfk = data; 1380 struct asus_rfkill *rfk = data;
@@ -1302,22 +1390,8 @@ static const struct rfkill_ops pega_rfkill_ops = {
1302static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk, 1390static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
1303 const char *name, int controlid, int rfkill_type) 1391 const char *name, int controlid, int rfkill_type)
1304{ 1392{
1305 int result; 1393 return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
1306 1394 &pega_rfkill_ops);
1307 rfk->control_id = controlid;
1308 rfk->asus = asus;
1309 rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
1310 rfkill_type, &pega_rfkill_ops, rfk);
1311 if (!rfk->rfkill)
1312 return -EINVAL;
1313
1314 result = rfkill_register(rfk->rfkill);
1315 if (result) {
1316 rfkill_destroy(rfk->rfkill);
1317 rfk->rfkill = NULL;
1318 }
1319
1320 return result;
1321} 1395}
1322 1396
1323static int pega_rfkill_init(struct asus_laptop *asus) 1397static int pega_rfkill_init(struct asus_laptop *asus)
@@ -1678,7 +1752,16 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1678 if (result) 1752 if (result)
1679 return result; 1753 return result;
1680 1754
1681 /* WLED and BLED are on by default */ 1755 if (!strcmp(bled_type, "led"))
1756 asus->bled_type = TYPE_LED;
1757 else if (!strcmp(bled_type, "rfkill"))
1758 asus->bled_type = TYPE_RFKILL;
1759
1760 if (!strcmp(wled_type, "led"))
1761 asus->wled_type = TYPE_LED;
1762 else if (!strcmp(wled_type, "rfkill"))
1763 asus->wled_type = TYPE_RFKILL;
1764
1682 if (bluetooth_status >= 0) 1765 if (bluetooth_status >= 0)
1683 asus_bluetooth_set(asus, !!bluetooth_status); 1766 asus_bluetooth_set(asus, !!bluetooth_status);
1684 1767