diff options
-rw-r--r-- | Documentation/ABI/testing/debugfs-ideapad | 19 | ||||
-rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 152 |
2 files changed, 171 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/debugfs-ideapad b/Documentation/ABI/testing/debugfs-ideapad new file mode 100644 index 000000000000..7079c0b21030 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-ideapad | |||
@@ -0,0 +1,19 @@ | |||
1 | What: /sys/kernel/debug/ideapad/cfg | ||
2 | Date: Sep 2011 | ||
3 | KernelVersion: 3.2 | ||
4 | Contact: Ike Panhc <ike.pan@canonical.com> | ||
5 | Description: | ||
6 | |||
7 | cfg shows the return value of _CFG method in VPC2004 device. It tells machine | ||
8 | capability and what graphic component within the machine. | ||
9 | |||
10 | |||
11 | What: /sys/kernel/debug/ideapad/status | ||
12 | Date: Sep 2011 | ||
13 | KernelVersion: 3.2 | ||
14 | Contact: Ike Panhc <ike.pan@canonical.com> | ||
15 | Description: | ||
16 | |||
17 | status shows infos we can read and tells its meaning and value. | ||
18 | |||
19 | |||
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 39a72a8aeb8c..1c8b5065f34c 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <linux/input/sparse-keymap.h> | 34 | #include <linux/input/sparse-keymap.h> |
35 | #include <linux/backlight.h> | 35 | #include <linux/backlight.h> |
36 | #include <linux/fb.h> | 36 | #include <linux/fb.h> |
37 | #include <linux/debugfs.h> | ||
38 | #include <linux/seq_file.h> | ||
37 | 39 | ||
38 | #define IDEAPAD_RFKILL_DEV_NUM (3) | 40 | #define IDEAPAD_RFKILL_DEV_NUM (3) |
39 | 41 | ||
@@ -71,10 +73,12 @@ struct ideapad_private { | |||
71 | struct platform_device *platform_device; | 73 | struct platform_device *platform_device; |
72 | struct input_dev *inputdev; | 74 | struct input_dev *inputdev; |
73 | struct backlight_device *blightdev; | 75 | struct backlight_device *blightdev; |
76 | struct dentry *debug; | ||
74 | unsigned long cfg; | 77 | unsigned long cfg; |
75 | }; | 78 | }; |
76 | 79 | ||
77 | static acpi_handle ideapad_handle; | 80 | static acpi_handle ideapad_handle; |
81 | static struct ideapad_private *ideapad_priv; | ||
78 | static bool no_bt_rfkill; | 82 | static bool no_bt_rfkill; |
79 | module_param(no_bt_rfkill, bool, 0444); | 83 | module_param(no_bt_rfkill, bool, 0444); |
80 | MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); | 84 | MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); |
@@ -188,6 +192,146 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) | |||
188 | } | 192 | } |
189 | 193 | ||
190 | /* | 194 | /* |
195 | * debugfs | ||
196 | */ | ||
197 | #define DEBUGFS_EVENT_LEN (4096) | ||
198 | static int debugfs_status_show(struct seq_file *s, void *data) | ||
199 | { | ||
200 | unsigned long value; | ||
201 | |||
202 | if (!read_ec_data(ideapad_handle, VPCCMD_R_BL_MAX, &value)) | ||
203 | seq_printf(s, "Backlight max:\t%lu\n", value); | ||
204 | if (!read_ec_data(ideapad_handle, VPCCMD_R_BL, &value)) | ||
205 | seq_printf(s, "Backlight now:\t%lu\n", value); | ||
206 | if (!read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &value)) | ||
207 | seq_printf(s, "BL power value:\t%s\n", value ? "On" : "Off"); | ||
208 | seq_printf(s, "=====================\n"); | ||
209 | |||
210 | if (!read_ec_data(ideapad_handle, VPCCMD_R_RF, &value)) | ||
211 | seq_printf(s, "Radio status:\t%s(%lu)\n", | ||
212 | value ? "On" : "Off", value); | ||
213 | if (!read_ec_data(ideapad_handle, VPCCMD_R_WIFI, &value)) | ||
214 | seq_printf(s, "Wifi status:\t%s(%lu)\n", | ||
215 | value ? "On" : "Off", value); | ||
216 | if (!read_ec_data(ideapad_handle, VPCCMD_R_BT, &value)) | ||
217 | seq_printf(s, "BT status:\t%s(%lu)\n", | ||
218 | value ? "On" : "Off", value); | ||
219 | if (!read_ec_data(ideapad_handle, VPCCMD_R_3G, &value)) | ||
220 | seq_printf(s, "3G status:\t%s(%lu)\n", | ||
221 | value ? "On" : "Off", value); | ||
222 | seq_printf(s, "=====================\n"); | ||
223 | |||
224 | if (!read_ec_data(ideapad_handle, VPCCMD_R_TOUCHPAD, &value)) | ||
225 | seq_printf(s, "Touchpad status:%s(%lu)\n", | ||
226 | value ? "On" : "Off", value); | ||
227 | if (!read_ec_data(ideapad_handle, VPCCMD_R_CAMERA, &value)) | ||
228 | seq_printf(s, "Camera status:\t%s(%lu)\n", | ||
229 | value ? "On" : "Off", value); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int debugfs_status_open(struct inode *inode, struct file *file) | ||
235 | { | ||
236 | return single_open(file, debugfs_status_show, NULL); | ||
237 | } | ||
238 | |||
239 | static const struct file_operations debugfs_status_fops = { | ||
240 | .owner = THIS_MODULE, | ||
241 | .open = debugfs_status_open, | ||
242 | .read = seq_read, | ||
243 | .llseek = seq_lseek, | ||
244 | .release = single_release, | ||
245 | }; | ||
246 | |||
247 | static int debugfs_cfg_show(struct seq_file *s, void *data) | ||
248 | { | ||
249 | if (!ideapad_priv) { | ||
250 | seq_printf(s, "cfg: N/A\n"); | ||
251 | } else { | ||
252 | seq_printf(s, "cfg: 0x%.8lX\n\nCapability: ", | ||
253 | ideapad_priv->cfg); | ||
254 | if (test_bit(CFG_BT_BIT, &ideapad_priv->cfg)) | ||
255 | seq_printf(s, "Bluetooth "); | ||
256 | if (test_bit(CFG_3G_BIT, &ideapad_priv->cfg)) | ||
257 | seq_printf(s, "3G "); | ||
258 | if (test_bit(CFG_WIFI_BIT, &ideapad_priv->cfg)) | ||
259 | seq_printf(s, "Wireless "); | ||
260 | if (test_bit(CFG_CAMERA_BIT, &ideapad_priv->cfg)) | ||
261 | seq_printf(s, "Camera "); | ||
262 | seq_printf(s, "\nGraphic: "); | ||
263 | switch ((ideapad_priv->cfg)&0x700) { | ||
264 | case 0x100: | ||
265 | seq_printf(s, "Intel"); | ||
266 | break; | ||
267 | case 0x200: | ||
268 | seq_printf(s, "ATI"); | ||
269 | break; | ||
270 | case 0x300: | ||
271 | seq_printf(s, "Nvidia"); | ||
272 | break; | ||
273 | case 0x400: | ||
274 | seq_printf(s, "Intel and ATI"); | ||
275 | break; | ||
276 | case 0x500: | ||
277 | seq_printf(s, "Intel and Nvidia"); | ||
278 | break; | ||
279 | } | ||
280 | seq_printf(s, "\n"); | ||
281 | } | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int debugfs_cfg_open(struct inode *inode, struct file *file) | ||
286 | { | ||
287 | return single_open(file, debugfs_cfg_show, NULL); | ||
288 | } | ||
289 | |||
290 | static const struct file_operations debugfs_cfg_fops = { | ||
291 | .owner = THIS_MODULE, | ||
292 | .open = debugfs_cfg_open, | ||
293 | .read = seq_read, | ||
294 | .llseek = seq_lseek, | ||
295 | .release = single_release, | ||
296 | }; | ||
297 | |||
298 | static int __devinit ideapad_debugfs_init(struct ideapad_private *priv) | ||
299 | { | ||
300 | struct dentry *node; | ||
301 | |||
302 | priv->debug = debugfs_create_dir("ideapad", NULL); | ||
303 | if (priv->debug == NULL) { | ||
304 | pr_err("failed to create debugfs directory"); | ||
305 | goto errout; | ||
306 | } | ||
307 | |||
308 | node = debugfs_create_file("cfg", S_IRUGO, priv->debug, NULL, | ||
309 | &debugfs_cfg_fops); | ||
310 | if (!node) { | ||
311 | pr_err("failed to create cfg in debugfs"); | ||
312 | goto errout; | ||
313 | } | ||
314 | |||
315 | node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL, | ||
316 | &debugfs_status_fops); | ||
317 | if (!node) { | ||
318 | pr_err("failed to create event in debugfs"); | ||
319 | goto errout; | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | |||
324 | errout: | ||
325 | return -ENOMEM; | ||
326 | } | ||
327 | |||
328 | static void ideapad_debugfs_exit(struct ideapad_private *priv) | ||
329 | { | ||
330 | debugfs_remove_recursive(priv->debug); | ||
331 | priv->debug = NULL; | ||
332 | } | ||
333 | |||
334 | /* | ||
191 | * sysfs | 335 | * sysfs |
192 | */ | 336 | */ |
193 | static ssize_t show_ideapad_cam(struct device *dev, | 337 | static ssize_t show_ideapad_cam(struct device *dev, |
@@ -573,6 +717,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) | |||
573 | if (!priv) | 717 | if (!priv) |
574 | return -ENOMEM; | 718 | return -ENOMEM; |
575 | dev_set_drvdata(&adevice->dev, priv); | 719 | dev_set_drvdata(&adevice->dev, priv); |
720 | ideapad_priv = priv; | ||
576 | ideapad_handle = adevice->handle; | 721 | ideapad_handle = adevice->handle; |
577 | priv->cfg = cfg; | 722 | priv->cfg = cfg; |
578 | 723 | ||
@@ -580,6 +725,10 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) | |||
580 | if (ret) | 725 | if (ret) |
581 | goto platform_failed; | 726 | goto platform_failed; |
582 | 727 | ||
728 | ret = ideapad_debugfs_init(priv); | ||
729 | if (ret) | ||
730 | goto debugfs_failed; | ||
731 | |||
583 | ret = ideapad_input_init(priv); | 732 | ret = ideapad_input_init(priv); |
584 | if (ret) | 733 | if (ret) |
585 | goto input_failed; | 734 | goto input_failed; |
@@ -605,6 +754,8 @@ backlight_failed: | |||
605 | ideapad_unregister_rfkill(adevice, i); | 754 | ideapad_unregister_rfkill(adevice, i); |
606 | ideapad_input_exit(priv); | 755 | ideapad_input_exit(priv); |
607 | input_failed: | 756 | input_failed: |
757 | ideapad_debugfs_exit(priv); | ||
758 | debugfs_failed: | ||
608 | ideapad_platform_exit(priv); | 759 | ideapad_platform_exit(priv); |
609 | platform_failed: | 760 | platform_failed: |
610 | kfree(priv); | 761 | kfree(priv); |
@@ -620,6 +771,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) | |||
620 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) | 771 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) |
621 | ideapad_unregister_rfkill(adevice, i); | 772 | ideapad_unregister_rfkill(adevice, i); |
622 | ideapad_input_exit(priv); | 773 | ideapad_input_exit(priv); |
774 | ideapad_debugfs_exit(priv); | ||
623 | ideapad_platform_exit(priv); | 775 | ideapad_platform_exit(priv); |
624 | dev_set_drvdata(&adevice->dev, NULL); | 776 | dev_set_drvdata(&adevice->dev, NULL); |
625 | kfree(priv); | 777 | kfree(priv); |