diff -uprN linux-3.16.1-org/drivers/platform/x86/apple-gmux.c linux-3.16.1-patched/drivers/platform/x86/apple-gmux.c --- a/drivers/platform/x86/apple-gmux.c 2014-08-14 04:36:35.000000000 +0200 +++ b/drivers/platform/x86/apple-gmux.c 2014-09-10 17:12:47.000000000 +0200 @@ -22,6 +22,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -39,10 +43,17 @@ struct apple_gmux_data { enum vga_switcheroo_client_id resume_client_id; enum vga_switcheroo_state power_state; struct completion powerchange_done; + + /*debugfs data*/ + struct dentry *debugfs_root; + struct dentry *switch_file; }; static struct apple_gmux_data *apple_gmux_data; +static int apple_gmux_debugfs_init(struct apple_gmux_data *gmux_data); +static void apple_gmux_debugfs_fini(struct apple_gmux_data *gmux_data); + /* * gmux port offsets. Many of these are not yet used, but may be in the * future, and it's useful to have them documented here anyhow. @@ -560,6 +571,7 @@ static int gmux_probe(struct pnp_dev *pn init_completion(&gmux_data->powerchange_done); apple_gmux_data = gmux_data; gmux_enable_interrupts(gmux_data); + apple_gmux_debugfs_init(gmux_data); return 0; @@ -584,6 +596,8 @@ static void gmux_remove(struct pnp_dev * { struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp); + apple_gmux_debugfs_fini(gmux_data); + vga_switcheroo_unregister_handler(); gmux_disable_interrupts(gmux_data); if (gmux_data->gpe >= 0) { @@ -604,6 +618,94 @@ static void gmux_remove(struct pnp_dev * apple_bl_register(); } +static int apple_gmux_show(struct seq_file *m, void *v) +{ + seq_printf(m, "Active Device: %s\nDiscrete Powered: %s\n", + gmux_active_client(apple_gmux_data) == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", + apple_gmux_data->power_state == VGA_SWITCHEROO_ON ? "ON" : "OFF" + ); + return 0; +} + +static int apple_gmux_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, apple_gmux_show, NULL); +} + +static ssize_t +apple_gmux_debugfs_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char usercmd[64]; + if (cnt > 63) + cnt = 63; + + if (copy_from_user(usercmd, ubuf, cnt)) + return -EFAULT; + + /*switch to IGD*/ + if (strncmp(usercmd, "IGD", 3) == 0) + gmux_switchto(VGA_SWITCHEROO_IGD); + + /*switch to DIS*/ + if (strncmp(usercmd, "DIS", 3) == 0) + gmux_switchto(VGA_SWITCHEROO_DIS); + + /*change power state*/ + if (strncmp(usercmd, "OFF", 3) == 0) + gmux_set_discrete_state(apple_gmux_data, VGA_SWITCHEROO_OFF); + + if (strncmp(usercmd, "ON", 2) == 0) + gmux_set_discrete_state(apple_gmux_data, VGA_SWITCHEROO_ON); + + return cnt; +} + +static const struct file_operations apple_gmux_debugfs_fops = { + .owner = THIS_MODULE, + .open = apple_gmux_debugfs_open, + .write = apple_gmux_debugfs_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void apple_gmux_debugfs_fini(struct apple_gmux_data *gmux_data) +{ + if (gmux_data->switch_file) { + debugfs_remove(gmux_data->switch_file); + gmux_data->switch_file = NULL; + } + if (gmux_data->debugfs_root) { + debugfs_remove(gmux_data->debugfs_root); + gmux_data->debugfs_root = NULL; + } +} + +static int apple_gmux_debugfs_init(struct apple_gmux_data *gmux_data) +{ + /* already initialised */ + if (gmux_data->debugfs_root) + return 0; + gmux_data->debugfs_root = debugfs_create_dir("applegmux", NULL); + + if (!gmux_data->debugfs_root) { + printk(KERN_ERR "apple_gmux: Cannot create /sys/kernel/debug/applegmux\n"); + goto fail; + } + + gmux_data->switch_file = debugfs_create_file("switch", 0644, + gmux_data->debugfs_root, NULL, &apple_gmux_debugfs_fops); + if (!gmux_data->switch_file) { + printk(KERN_ERR "apple_gmux: cannot create /sys/kernel/debug/applegmux/switch\n"); + goto fail; + } + return 0; +fail: + apple_gmux_debugfs_fini(gmux_data); + return -1; +} + static const struct pnp_device_id gmux_device_ids[] = { {"APP000B", 0}, {"", 0}