summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Forshee <seth.forshee@canonical.com>2012-09-07 10:22:06 -0500
committerDave Airlie <airlied@gmail.com>2012-10-04 06:23:00 -0400
commitd68a2b0a52f88ed5d14d506e70ecfa2a97b52d92 (patch)
tree63d934bb5f2e0312a5ad1cd131c21899ec276ec2
parent1e9808b42ef8889ea017f1d24ba689a76028af5a (diff)
vga_switcheroo: Add notifier call chain for switcheroo events
DRM needs to be notified of client and handler registration in order to defer initialization of the secondary GPU until the EDID can be read from the LVDS panel. To support this add a notifier call chain to vga_switcheroo for subscribing to switcheroo events. Events are generated for registration and unregistration of handlers and clients. Signed-off-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: Dave Airlie <airlied@gmail.com>
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c34
-rw-r--r--include/linux/vga_switcheroo.h14
2 files changed, 48 insertions, 0 deletions
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index e53f67d498a3..d5cd2747bdc3 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -24,6 +24,7 @@
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/fb.h>
+#include <linux/notifier.h>
#include <linux/pci.h>
#include <linux/vga_switcheroo.h>
@@ -70,6 +71,28 @@ static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
};
+static BLOCKING_NOTIFIER_HEAD(vga_switcheroo_notifier_list);
+
+int vga_switcheroo_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&vga_switcheroo_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_register_notifier);
+
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&vga_switcheroo_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_notifier);
+
+static int vga_switcheroo_notifier_call_chain(enum vga_switcheroo_event event)
+{
+ return blocking_notifier_call_chain(&vga_switcheroo_notifier_list,
+ event, NULL);
+}
+
static bool vga_switcheroo_ready(void)
{
/* we're ready if we get two clients + handler */
@@ -113,10 +136,18 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
vga_switcheroo_enable();
}
mutex_unlock(&vgasr_mutex);
+
+ vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_REGISTERED);
return 0;
}
EXPORT_SYMBOL(vga_switcheroo_register_handler);
+bool vga_switcheroo_handler_registered(void)
+{
+ return !!vgasr_priv.handler;
+}
+EXPORT_SYMBOL(vga_switcheroo_handler_registered);
+
void vga_switcheroo_unregister_handler(void)
{
mutex_lock(&vgasr_mutex);
@@ -127,6 +158,7 @@ void vga_switcheroo_unregister_handler(void)
vgasr_priv.active = false;
}
mutex_unlock(&vgasr_mutex);
+ vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_HANDLER_UNREGISTERED);
}
EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
@@ -156,6 +188,7 @@ static int register_client(struct pci_dev *pdev,
vga_switcheroo_enable();
}
mutex_unlock(&vgasr_mutex);
+ vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_REGISTERED);
return 0;
}
@@ -250,6 +283,7 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
vgasr_priv.active = false;
}
mutex_unlock(&vgasr_mutex);
+ vga_switcheroo_notifier_call_chain(VGA_SWITCHEROO_CLIENT_UNREGISTERED);
}
EXPORT_SYMBOL(vga_switcheroo_unregister_client);
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index e36185800858..c3d7c6fd01ca 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -11,6 +11,7 @@
#define _LINUX_VGA_SWITCHEROO_H_
#include <linux/fb.h>
+#include <linux/notifier.h>
struct pci_dev;
@@ -28,6 +29,13 @@ enum vga_switcheroo_client_id {
VGA_SWITCHEROO_MAX_CLIENTS,
};
+enum vga_switcheroo_event {
+ VGA_SWITCHEROO_CLIENT_REGISTERED,
+ VGA_SWITCHEROO_CLIENT_UNREGISTERED,
+ VGA_SWITCHEROO_HANDLER_REGISTERED,
+ VGA_SWITCHEROO_HANDLER_UNREGISTERED,
+};
+
struct vga_switcheroo_handler {
int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
@@ -44,6 +52,9 @@ struct vga_switcheroo_client_ops {
};
#if defined(CONFIG_VGA_SWITCHEROO)
+int vga_switcheroo_register_notifier(struct notifier_block *nb);
+int vga_switcheroo_unregister_notifier(struct notifier_block *nb);
+bool vga_switcheroo_handler_registered(void);
void vga_switcheroo_unregister_client(struct pci_dev *dev);
int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops);
@@ -66,6 +77,9 @@ int vga_switcheroo_get_client_state(struct pci_dev *dev);
#else
+static inline int vga_switcheroo_register_notifier(struct notifier_block *nb) { return 0; }
+static inline int vga_switcheroo_unregister_notifier(struct notifier_block *nb) { return 0; }
+static inline bool vga_switcheroo_handler_registered(void) { return false; }
static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops) { return 0; }