aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorCorentin Chary <corentin.chary@gmail.com>2011-12-15 02:27:34 -0500
committerMatthew Garrett <mjg@redhat.com>2012-03-20 12:02:16 -0400
commit774b06780be20d07c5459becd6495c04523a93a2 (patch)
treefc91522465fd85a9e48f6736545214e2fd60eca8 /drivers/platform
parent40969c7dd6298718820e0818b5b5acef7b24923d (diff)
asus-laptop: control how BLED and WLED should be exposed
Let the user tells if BLED and WLED should be exposed as led or rfkill (the old sysfs are still here, but this adds a standard interface to control the device). For example on my A6JC, with WAPF=1, I would do: $ modprobe asus-laptop wled_type=led bluetooth_type=rfkill There is still no known way to automatically guess what BLED and WLED methods will control, it's why user information is needed. A userspace database could do that automatically, and maybe some DMI matching in the driver. Signed-off-by: Corentin Chary <corentin.chary@gmail.com> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-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