diff options
author | Corentin Chary <corentincj@iksaif.net> | 2011-11-26 05:00:03 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2012-03-20 12:02:08 -0400 |
commit | 5b80fc40e5c53da2c69382c20cfc2ece19ece9ce (patch) | |
tree | 42080e2e731acd938bc56bc0000e6ca99cbab147 /drivers/platform/x86/samsung-laptop.c | |
parent | 7e9607118b08bd4e1dae65d56e425e8de7f3da1c (diff) |
samsung-laptop: add a small debugfs interface
This allow to call arbitrary sabi commands wihout
modifying the driver at all. For example, setting
the keyboard backlight brightness to 5 using debugfs
interface can be done like that:
; Set the command
echo 0x78 > command
; Set the data
echo 0x0582 > d0
; Fill the rest with 0
echo 0 > d1
echo 0 > d2
echo 0 > d3
; And issue the command
cat call
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/samsung-laptop.c')
-rw-r--r-- | drivers/platform/x86/samsung-laptop.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 134444f176e6..d15b6874b1b2 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/rfkill.h> | 23 | #include <linux/rfkill.h> |
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/debugfs.h> | ||
25 | 27 | ||
26 | /* | 28 | /* |
27 | * This driver is needed because a number of Samsung laptops do not hook | 29 | * This driver is needed because a number of Samsung laptops do not hook |
@@ -226,6 +228,35 @@ static const struct sabi_config sabi_configs[] = { | |||
226 | { }, | 228 | { }, |
227 | }; | 229 | }; |
228 | 230 | ||
231 | /* | ||
232 | * samsung-laptop/ - debugfs root directory | ||
233 | * f0000_segment - dump f0000 segment | ||
234 | * command - current command | ||
235 | * data - current data | ||
236 | * d0, d1, d2, d3 - data fields | ||
237 | * call - call SABI using command and data | ||
238 | * | ||
239 | * This allow to call arbitrary sabi commands wihout | ||
240 | * modifying the driver at all. | ||
241 | * For example, setting the keyboard backlight brightness to 5 | ||
242 | * | ||
243 | * echo 0x78 > command | ||
244 | * echo 0x0582 > d0 | ||
245 | * echo 0 > d1 | ||
246 | * echo 0 > d2 | ||
247 | * echo 0 > d3 | ||
248 | * cat call | ||
249 | */ | ||
250 | |||
251 | struct samsung_laptop_debug { | ||
252 | struct dentry *root; | ||
253 | struct sabi_data data; | ||
254 | u16 command; | ||
255 | |||
256 | struct debugfs_blob_wrapper f0000_wrapper; | ||
257 | struct debugfs_blob_wrapper data_wrapper; | ||
258 | }; | ||
259 | |||
229 | struct samsung_laptop { | 260 | struct samsung_laptop { |
230 | const struct sabi_config *config; | 261 | const struct sabi_config *config; |
231 | 262 | ||
@@ -239,6 +270,8 @@ struct samsung_laptop { | |||
239 | struct backlight_device *backlight_device; | 270 | struct backlight_device *backlight_device; |
240 | struct rfkill *rfk; | 271 | struct rfkill *rfk; |
241 | 272 | ||
273 | struct samsung_laptop_debug debug; | ||
274 | |||
242 | bool handle_backlight; | 275 | bool handle_backlight; |
243 | bool has_stepping_quirk; | 276 | bool has_stepping_quirk; |
244 | }; | 277 | }; |
@@ -680,6 +713,113 @@ static int __init samsung_sysfs_init(struct samsung_laptop *samsung) | |||
680 | 713 | ||
681 | } | 714 | } |
682 | 715 | ||
716 | static int show_call(struct seq_file *m, void *data) | ||
717 | { | ||
718 | struct samsung_laptop *samsung = m->private; | ||
719 | struct sabi_data *sdata = &samsung->debug.data; | ||
720 | int ret; | ||
721 | |||
722 | seq_printf(m, "SABI 0x%04x {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n", | ||
723 | samsung->debug.command, | ||
724 | sdata->d0, sdata->d1, sdata->d2, sdata->d3); | ||
725 | |||
726 | ret = sabi_command(samsung, samsung->debug.command, sdata, sdata); | ||
727 | |||
728 | if (ret) { | ||
729 | seq_printf(m, "SABI command 0x%04x failed\n", | ||
730 | samsung->debug.command); | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | seq_printf(m, "SABI {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n", | ||
735 | sdata->d0, sdata->d1, sdata->d2, sdata->d3); | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int samsung_debugfs_open(struct inode *inode, struct file *file) | ||
740 | { | ||
741 | return single_open(file, show_call, inode->i_private); | ||
742 | } | ||
743 | |||
744 | static const struct file_operations samsung_laptop_call_io_ops = { | ||
745 | .owner = THIS_MODULE, | ||
746 | .open = samsung_debugfs_open, | ||
747 | .read = seq_read, | ||
748 | .llseek = seq_lseek, | ||
749 | .release = single_release, | ||
750 | }; | ||
751 | |||
752 | static void samsung_debugfs_exit(struct samsung_laptop *samsung) | ||
753 | { | ||
754 | debugfs_remove_recursive(samsung->debug.root); | ||
755 | } | ||
756 | |||
757 | static int samsung_debugfs_init(struct samsung_laptop *samsung) | ||
758 | { | ||
759 | struct dentry *dent; | ||
760 | |||
761 | samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL); | ||
762 | if (!samsung->debug.root) { | ||
763 | pr_err("failed to create debugfs directory"); | ||
764 | goto error_debugfs; | ||
765 | } | ||
766 | |||
767 | samsung->debug.f0000_wrapper.data = samsung->f0000_segment; | ||
768 | samsung->debug.f0000_wrapper.size = 0xffff; | ||
769 | |||
770 | samsung->debug.data_wrapper.data = &samsung->debug.data; | ||
771 | samsung->debug.data_wrapper.size = sizeof(samsung->debug.data); | ||
772 | |||
773 | dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR, | ||
774 | samsung->debug.root, &samsung->debug.command); | ||
775 | if (!dent) | ||
776 | goto error_debugfs; | ||
777 | |||
778 | dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root, | ||
779 | &samsung->debug.data.d0); | ||
780 | if (!dent) | ||
781 | goto error_debugfs; | ||
782 | |||
783 | dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root, | ||
784 | &samsung->debug.data.d1); | ||
785 | if (!dent) | ||
786 | goto error_debugfs; | ||
787 | |||
788 | dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root, | ||
789 | &samsung->debug.data.d2); | ||
790 | if (!dent) | ||
791 | goto error_debugfs; | ||
792 | |||
793 | dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root, | ||
794 | &samsung->debug.data.d3); | ||
795 | if (!dent) | ||
796 | goto error_debugfs; | ||
797 | |||
798 | dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR, | ||
799 | samsung->debug.root, | ||
800 | &samsung->debug.data_wrapper); | ||
801 | if (!dent) | ||
802 | goto error_debugfs; | ||
803 | |||
804 | dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR, | ||
805 | samsung->debug.root, | ||
806 | &samsung->debug.f0000_wrapper); | ||
807 | if (!dent) | ||
808 | goto error_debugfs; | ||
809 | |||
810 | dent = debugfs_create_file("call", S_IFREG | S_IRUGO, | ||
811 | samsung->debug.root, samsung, | ||
812 | &samsung_laptop_call_io_ops); | ||
813 | if (!dent) | ||
814 | goto error_debugfs; | ||
815 | |||
816 | return 0; | ||
817 | |||
818 | error_debugfs: | ||
819 | samsung_debugfs_exit(samsung); | ||
820 | return -ENOMEM; | ||
821 | } | ||
822 | |||
683 | static void samsung_sabi_exit(struct samsung_laptop *samsung) | 823 | static void samsung_sabi_exit(struct samsung_laptop *samsung) |
684 | { | 824 | { |
685 | const struct sabi_config *config = samsung->config; | 825 | const struct sabi_config *config = samsung->config; |
@@ -1123,9 +1263,15 @@ static int __init samsung_init(void) | |||
1123 | if (ret) | 1263 | if (ret) |
1124 | goto error_rfkill; | 1264 | goto error_rfkill; |
1125 | 1265 | ||
1266 | ret = samsung_debugfs_init(samsung); | ||
1267 | if (ret) | ||
1268 | goto error_debugfs; | ||
1269 | |||
1126 | samsung_platform_device = samsung->platform_device; | 1270 | samsung_platform_device = samsung->platform_device; |
1127 | return ret; | 1271 | return ret; |
1128 | 1272 | ||
1273 | error_debugfs: | ||
1274 | samsung_rfkill_exit(samsung); | ||
1129 | error_rfkill: | 1275 | error_rfkill: |
1130 | samsung_backlight_exit(samsung); | 1276 | samsung_backlight_exit(samsung); |
1131 | error_backlight: | 1277 | error_backlight: |
@@ -1145,6 +1291,7 @@ static void __exit samsung_exit(void) | |||
1145 | 1291 | ||
1146 | samsung = platform_get_drvdata(samsung_platform_device); | 1292 | samsung = platform_get_drvdata(samsung_platform_device); |
1147 | 1293 | ||
1294 | samsung_debugfs_exit(samsung); | ||
1148 | samsung_rfkill_exit(samsung); | 1295 | samsung_rfkill_exit(samsung); |
1149 | samsung_backlight_exit(samsung); | 1296 | samsung_backlight_exit(samsung); |
1150 | samsung_sysfs_exit(samsung); | 1297 | samsung_sysfs_exit(samsung); |