diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/asus-laptop.c | 149 |
1 files changed, 116 insertions, 33 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index db32d0337a7c..e416867c0725 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
@@ -81,6 +81,19 @@ static uint wapf = 1; | |||
81 | module_param(wapf, uint, 0444); | 81 | module_param(wapf, uint, 0444); |
82 | MODULE_PARM_DESC(wapf, "WAPF value"); | 82 | MODULE_PARM_DESC(wapf, "WAPF value"); |
83 | 83 | ||
84 | static char *wled_type = "unknown"; | ||
85 | static char *bled_type = "unknown"; | ||
86 | |||
87 | module_param(wled_type, charp, 0444); | ||
88 | MODULE_PARM_DESC(wlan_status, "Set the wled type on boot " | ||
89 | "(unknown, led or rfkill). " | ||
90 | "default is unknown"); | ||
91 | |||
92 | module_param(bled_type, charp, 0444); | ||
93 | MODULE_PARM_DESC(bled_type, "Set the bled type on boot " | ||
94 | "(unknown, led or rfkill). " | ||
95 | "default is unknown"); | ||
96 | |||
84 | static int wlan_status = 1; | 97 | static int wlan_status = 1; |
85 | static int bluetooth_status = 1; | 98 | static int bluetooth_status = 1; |
86 | static int wimax_status = -1; | 99 | static 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 | */ |
221 | struct asus_rfkill { | 239 | struct 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 | ||
601 | static void asus_led_exit(struct asus_laptop *asus) | 624 | static 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 | ||
642 | static int asus_led_init(struct asus_laptop *asus) | 669 | static 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 | */ |
968 | static int asus_bluetooth_set(struct asus_laptop *asus, int status) | 1005 | static 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 | ||
1285 | static 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 | |||
1298 | static const struct rfkill_ops asus_rfkill_ops = { | ||
1299 | .set_block = asus_rfkill_set, | ||
1300 | }; | ||
1301 | |||
1248 | static void asus_rfkill_terminate(struct asus_rfkill *rfk) | 1302 | static 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 | ||
1266 | static int asus_rfkill_init(struct asus_laptop *asus) | 1320 | static 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 | ||
1342 | static 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 | |||
1371 | exit: | ||
1372 | if (result) | ||
1373 | asus_rfkill_exit(asus); | ||
1374 | |||
1375 | return result; | ||
1376 | } | ||
1377 | |||
1290 | static int pega_rfkill_set(void *data, bool blocked) | 1378 | static 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 = { | |||
1302 | static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk, | 1390 | static 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 | ||
1323 | static int pega_rfkill_init(struct asus_laptop *asus) | 1397 | static 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 | ||