aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-04-26 08:29:48 -0400
committerTakashi Iwai <tiwai@suse.de>2012-05-13 05:27:21 -0400
commit3e9e63dbd3745ba9ea10f0f86c93f4086c89d5b8 (patch)
tree89c5fc0208943b3714865950935ad8bf70b6386a /drivers/gpu
parent26ec685ff9d9c16525d8ec4c97e52fcdb187b302 (diff)
vga_switcheroo: Add the support for audio clients
Add the support for audio clients to VGA-switcheroo for handling the HDMI audio controller together with VGA switching. The id of the audio controller should be given explicitly at registration time unlike the video controller. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=43155 Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c70
1 files changed, 56 insertions, 14 deletions
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index a049b743cad0..38f9534ac513 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -57,6 +57,11 @@ struct vgasr_priv {
57 struct vga_switcheroo_handler *handler; 57 struct vga_switcheroo_handler *handler;
58}; 58};
59 59
60#define ID_BIT_AUDIO 0x100
61#define client_is_audio(c) ((c)->id & ID_BIT_AUDIO)
62#define client_is_vga(c) ((c)->id == -1 || !client_is_audio(c))
63#define client_id(c) ((c)->id & ~ID_BIT_AUDIO)
64
60static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv); 65static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
61static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv); 66static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
62 67
@@ -96,6 +101,8 @@ static void vga_switcheroo_enable(void)
96 vgasr_priv.handler->init(); 101 vgasr_priv.handler->init();
97 102
98 list_for_each_entry(client, &vgasr_priv.clients, list) { 103 list_for_each_entry(client, &vgasr_priv.clients, list) {
104 if (client->id != -1)
105 continue;
99 ret = vgasr_priv.handler->get_client_id(client->pdev); 106 ret = vgasr_priv.handler->get_client_id(client->pdev);
100 if (ret < 0) 107 if (ret < 0)
101 return; 108 return;
@@ -106,8 +113,9 @@ static void vga_switcheroo_enable(void)
106 vgasr_priv.active = true; 113 vgasr_priv.active = true;
107} 114}
108 115
109int vga_switcheroo_register_client(struct pci_dev *pdev, 116static int register_client(struct pci_dev *pdev,
110 const struct vga_switcheroo_client_ops *ops) 117 const struct vga_switcheroo_client_ops *ops,
118 int id, bool active)
111{ 119{
112 struct vga_switcheroo_client *client; 120 struct vga_switcheroo_client *client;
113 121
@@ -118,24 +126,40 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
118 client->pwr_state = VGA_SWITCHEROO_ON; 126 client->pwr_state = VGA_SWITCHEROO_ON;
119 client->pdev = pdev; 127 client->pdev = pdev;
120 client->ops = ops; 128 client->ops = ops;
121 client->id = -1; 129 client->id = id;
122 if (pdev == vga_default_device()) 130 client->active = active;
123 client->active = true;
124 131
125 mutex_lock(&vgasr_mutex); 132 mutex_lock(&vgasr_mutex);
126 list_add_tail(&client->list, &vgasr_priv.clients); 133 list_add_tail(&client->list, &vgasr_priv.clients);
127 vgasr_priv.registered_clients++; 134 if (client_is_vga(client))
135 vgasr_priv.registered_clients++;
128 136
129 /* if we get two clients + handler */ 137 /* if we get two clients + handler */
130 if (vgasr_priv.registered_clients == 2 && vgasr_priv.handler) { 138 if (!vgasr_priv.active &&
139 vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
131 printk(KERN_INFO "vga_switcheroo: enabled\n"); 140 printk(KERN_INFO "vga_switcheroo: enabled\n");
132 vga_switcheroo_enable(); 141 vga_switcheroo_enable();
133 } 142 }
134 mutex_unlock(&vgasr_mutex); 143 mutex_unlock(&vgasr_mutex);
135 return 0; 144 return 0;
136} 145}
146
147int vga_switcheroo_register_client(struct pci_dev *pdev,
148 const struct vga_switcheroo_client_ops *ops)
149{
150 return register_client(pdev, ops, -1,
151 pdev == vga_default_device());
152}
137EXPORT_SYMBOL(vga_switcheroo_register_client); 153EXPORT_SYMBOL(vga_switcheroo_register_client);
138 154
155int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
156 const struct vga_switcheroo_client_ops *ops,
157 int id, bool active)
158{
159 return register_client(pdev, ops, id | ID_BIT_AUDIO, active);
160}
161EXPORT_SYMBOL(vga_switcheroo_register_audio_client);
162
139static struct vga_switcheroo_client * 163static struct vga_switcheroo_client *
140find_client_from_pci(struct list_head *head, struct pci_dev *pdev) 164find_client_from_pci(struct list_head *head, struct pci_dev *pdev)
141{ 165{
@@ -161,7 +185,7 @@ find_active_client(struct list_head *head)
161{ 185{
162 struct vga_switcheroo_client *client; 186 struct vga_switcheroo_client *client;
163 list_for_each_entry(client, head, list) 187 list_for_each_entry(client, head, list)
164 if (client->active == true) 188 if (client->active && client_is_vga(client))
165 return client; 189 return client;
166 return NULL; 190 return NULL;
167} 191}
@@ -173,13 +197,16 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
173 mutex_lock(&vgasr_mutex); 197 mutex_lock(&vgasr_mutex);
174 client = find_client_from_pci(&vgasr_priv.clients, pdev); 198 client = find_client_from_pci(&vgasr_priv.clients, pdev);
175 if (client) { 199 if (client) {
200 if (client_is_vga(client))
201 vgasr_priv.registered_clients--;
176 list_del(&client->list); 202 list_del(&client->list);
177 kfree(client); 203 kfree(client);
178 vgasr_priv.registered_clients--;
179 } 204 }
180 printk(KERN_INFO "vga_switcheroo: disabled\n"); 205 if (vgasr_priv.active && vgasr_priv.registered_clients < 2) {
181 vga_switcheroo_debugfs_fini(&vgasr_priv); 206 printk(KERN_INFO "vga_switcheroo: disabled\n");
182 vgasr_priv.active = false; 207 vga_switcheroo_debugfs_fini(&vgasr_priv);
208 vgasr_priv.active = false;
209 }
183 mutex_unlock(&vgasr_mutex); 210 mutex_unlock(&vgasr_mutex);
184} 211}
185EXPORT_SYMBOL(vga_switcheroo_unregister_client); 212EXPORT_SYMBOL(vga_switcheroo_unregister_client);
@@ -203,8 +230,9 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
203 int i = 0; 230 int i = 0;
204 mutex_lock(&vgasr_mutex); 231 mutex_lock(&vgasr_mutex);
205 list_for_each_entry(client, &vgasr_priv.clients, list) { 232 list_for_each_entry(client, &vgasr_priv.clients, list) {
206 seq_printf(m, "%d:%s:%c:%s:%s\n", i, 233 seq_printf(m, "%d:%s%s:%c:%s:%s\n", i,
207 client->id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", 234 client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
235 client_is_vga(client) ? "" : "-Audio",
208 client->active ? '+' : ' ', 236 client->active ? '+' : ' ',
209 client->pwr_state ? "Pwr" : "Off", 237 client->pwr_state ? "Pwr" : "Off",
210 pci_name(client->pdev)); 238 pci_name(client->pdev));
@@ -239,6 +267,17 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
239 return 0; 267 return 0;
240} 268}
241 269
270static void set_audio_state(int id, int state)
271{
272 struct vga_switcheroo_client *client;
273
274 client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
275 if (client && client->pwr_state != state) {
276 client->ops->set_gpu_state(client->pdev, state);
277 client->pwr_state = state;
278 }
279}
280
242/* stage one happens before delay */ 281/* stage one happens before delay */
243static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) 282static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
244{ 283{
@@ -252,6 +291,7 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
252 vga_switchon(new_client); 291 vga_switchon(new_client);
253 292
254 vga_set_default_device(new_client->pdev); 293 vga_set_default_device(new_client->pdev);
294 set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
255 295
256 return 0; 296 return 0;
257} 297}
@@ -281,6 +321,8 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
281 if (new_client->ops->reprobe) 321 if (new_client->ops->reprobe)
282 new_client->ops->reprobe(new_client->pdev); 322 new_client->ops->reprobe(new_client->pdev);
283 323
324 set_audio_state(active->id, VGA_SWITCHEROO_OFF);
325
284 if (active->pwr_state == VGA_SWITCHEROO_ON) 326 if (active->pwr_state == VGA_SWITCHEROO_ON)
285 vga_switchoff(active); 327 vga_switchoff(active);
286 328