diff options
Diffstat (limited to 'drivers/gpu/vga/vga_switcheroo.c')
-rw-r--r-- | drivers/gpu/vga/vga_switcheroo.c | 284 |
1 files changed, 166 insertions, 118 deletions
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 58434e804d91..38f9534ac513 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c | |||
@@ -28,15 +28,16 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/vga_switcheroo.h> | 29 | #include <linux/vga_switcheroo.h> |
30 | 30 | ||
31 | #include <linux/vgaarb.h> | ||
32 | |||
31 | struct vga_switcheroo_client { | 33 | struct vga_switcheroo_client { |
32 | struct pci_dev *pdev; | 34 | struct pci_dev *pdev; |
33 | struct fb_info *fb_info; | 35 | struct fb_info *fb_info; |
34 | int pwr_state; | 36 | int pwr_state; |
35 | void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state); | 37 | const struct vga_switcheroo_client_ops *ops; |
36 | void (*reprobe)(struct pci_dev *pdev); | ||
37 | bool (*can_switch)(struct pci_dev *pdev); | ||
38 | int id; | 38 | int id; |
39 | bool active; | 39 | bool active; |
40 | struct list_head list; | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | static DEFINE_MUTEX(vgasr_mutex); | 43 | static DEFINE_MUTEX(vgasr_mutex); |
@@ -51,16 +52,23 @@ struct vgasr_priv { | |||
51 | struct dentry *switch_file; | 52 | struct dentry *switch_file; |
52 | 53 | ||
53 | int registered_clients; | 54 | int registered_clients; |
54 | struct vga_switcheroo_client clients[VGA_SWITCHEROO_MAX_CLIENTS]; | 55 | struct list_head clients; |
55 | 56 | ||
56 | struct vga_switcheroo_handler *handler; | 57 | struct vga_switcheroo_handler *handler; |
57 | }; | 58 | }; |
58 | 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 | |||
59 | static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv); | 65 | static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv); |
60 | static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv); | 66 | static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv); |
61 | 67 | ||
62 | /* only one switcheroo per system */ | 68 | /* only one switcheroo per system */ |
63 | static struct vgasr_priv vgasr_priv; | 69 | static struct vgasr_priv vgasr_priv = { |
70 | .clients = LIST_HEAD_INIT(vgasr_priv.clients), | ||
71 | }; | ||
64 | 72 | ||
65 | int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) | 73 | int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) |
66 | { | 74 | { |
@@ -86,72 +94,119 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_handler); | |||
86 | 94 | ||
87 | static void vga_switcheroo_enable(void) | 95 | static void vga_switcheroo_enable(void) |
88 | { | 96 | { |
89 | int i; | ||
90 | int ret; | 97 | int ret; |
98 | struct vga_switcheroo_client *client; | ||
99 | |||
91 | /* call the handler to init */ | 100 | /* call the handler to init */ |
92 | vgasr_priv.handler->init(); | 101 | vgasr_priv.handler->init(); |
93 | 102 | ||
94 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 103 | list_for_each_entry(client, &vgasr_priv.clients, list) { |
95 | ret = vgasr_priv.handler->get_client_id(vgasr_priv.clients[i].pdev); | 104 | if (client->id != -1) |
105 | continue; | ||
106 | ret = vgasr_priv.handler->get_client_id(client->pdev); | ||
96 | if (ret < 0) | 107 | if (ret < 0) |
97 | return; | 108 | return; |
98 | 109 | ||
99 | vgasr_priv.clients[i].id = ret; | 110 | client->id = ret; |
100 | } | 111 | } |
101 | vga_switcheroo_debugfs_init(&vgasr_priv); | 112 | vga_switcheroo_debugfs_init(&vgasr_priv); |
102 | vgasr_priv.active = true; | 113 | vgasr_priv.active = true; |
103 | } | 114 | } |
104 | 115 | ||
105 | int vga_switcheroo_register_client(struct pci_dev *pdev, | 116 | static int register_client(struct pci_dev *pdev, |
106 | void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state), | 117 | const struct vga_switcheroo_client_ops *ops, |
107 | void (*reprobe)(struct pci_dev *pdev), | 118 | int id, bool active) |
108 | bool (*can_switch)(struct pci_dev *pdev)) | ||
109 | { | 119 | { |
110 | int index; | 120 | struct vga_switcheroo_client *client; |
121 | |||
122 | client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
123 | if (!client) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | client->pwr_state = VGA_SWITCHEROO_ON; | ||
127 | client->pdev = pdev; | ||
128 | client->ops = ops; | ||
129 | client->id = id; | ||
130 | client->active = active; | ||
111 | 131 | ||
112 | mutex_lock(&vgasr_mutex); | 132 | mutex_lock(&vgasr_mutex); |
113 | /* don't do IGD vs DIS here */ | 133 | list_add_tail(&client->list, &vgasr_priv.clients); |
114 | if (vgasr_priv.registered_clients & 1) | 134 | if (client_is_vga(client)) |
115 | index = 1; | 135 | vgasr_priv.registered_clients++; |
116 | else | ||
117 | index = 0; | ||
118 | |||
119 | vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON; | ||
120 | vgasr_priv.clients[index].pdev = pdev; | ||
121 | vgasr_priv.clients[index].set_gpu_state = set_gpu_state; | ||
122 | vgasr_priv.clients[index].reprobe = reprobe; | ||
123 | vgasr_priv.clients[index].can_switch = can_switch; | ||
124 | vgasr_priv.clients[index].id = -1; | ||
125 | if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) | ||
126 | vgasr_priv.clients[index].active = true; | ||
127 | |||
128 | vgasr_priv.registered_clients |= (1 << index); | ||
129 | 136 | ||
130 | /* if we get two clients + handler */ | 137 | /* if we get two clients + handler */ |
131 | if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) { | 138 | if (!vgasr_priv.active && |
139 | vgasr_priv.registered_clients == 2 && vgasr_priv.handler) { | ||
132 | printk(KERN_INFO "vga_switcheroo: enabled\n"); | 140 | printk(KERN_INFO "vga_switcheroo: enabled\n"); |
133 | vga_switcheroo_enable(); | 141 | vga_switcheroo_enable(); |
134 | } | 142 | } |
135 | mutex_unlock(&vgasr_mutex); | 143 | mutex_unlock(&vgasr_mutex); |
136 | return 0; | 144 | return 0; |
137 | } | 145 | } |
146 | |||
147 | int 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 | } | ||
138 | EXPORT_SYMBOL(vga_switcheroo_register_client); | 153 | EXPORT_SYMBOL(vga_switcheroo_register_client); |
139 | 154 | ||
155 | int 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 | } | ||
161 | EXPORT_SYMBOL(vga_switcheroo_register_audio_client); | ||
162 | |||
163 | static struct vga_switcheroo_client * | ||
164 | find_client_from_pci(struct list_head *head, struct pci_dev *pdev) | ||
165 | { | ||
166 | struct vga_switcheroo_client *client; | ||
167 | list_for_each_entry(client, head, list) | ||
168 | if (client->pdev == pdev) | ||
169 | return client; | ||
170 | return NULL; | ||
171 | } | ||
172 | |||
173 | static struct vga_switcheroo_client * | ||
174 | find_client_from_id(struct list_head *head, int client_id) | ||
175 | { | ||
176 | struct vga_switcheroo_client *client; | ||
177 | list_for_each_entry(client, head, list) | ||
178 | if (client->id == client_id) | ||
179 | return client; | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | static struct vga_switcheroo_client * | ||
184 | find_active_client(struct list_head *head) | ||
185 | { | ||
186 | struct vga_switcheroo_client *client; | ||
187 | list_for_each_entry(client, head, list) | ||
188 | if (client->active && client_is_vga(client)) | ||
189 | return client; | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
140 | void vga_switcheroo_unregister_client(struct pci_dev *pdev) | 193 | void vga_switcheroo_unregister_client(struct pci_dev *pdev) |
141 | { | 194 | { |
142 | int i; | 195 | struct vga_switcheroo_client *client; |
143 | 196 | ||
144 | mutex_lock(&vgasr_mutex); | 197 | mutex_lock(&vgasr_mutex); |
145 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 198 | client = find_client_from_pci(&vgasr_priv.clients, pdev); |
146 | if (vgasr_priv.clients[i].pdev == pdev) { | 199 | if (client) { |
147 | vgasr_priv.registered_clients &= ~(1 << i); | 200 | if (client_is_vga(client)) |
148 | break; | 201 | vgasr_priv.registered_clients--; |
149 | } | 202 | list_del(&client->list); |
203 | kfree(client); | ||
204 | } | ||
205 | if (vgasr_priv.active && vgasr_priv.registered_clients < 2) { | ||
206 | printk(KERN_INFO "vga_switcheroo: disabled\n"); | ||
207 | vga_switcheroo_debugfs_fini(&vgasr_priv); | ||
208 | vgasr_priv.active = false; | ||
150 | } | 209 | } |
151 | |||
152 | printk(KERN_INFO "vga_switcheroo: disabled\n"); | ||
153 | vga_switcheroo_debugfs_fini(&vgasr_priv); | ||
154 | vgasr_priv.active = false; | ||
155 | mutex_unlock(&vgasr_mutex); | 210 | mutex_unlock(&vgasr_mutex); |
156 | } | 211 | } |
157 | EXPORT_SYMBOL(vga_switcheroo_unregister_client); | 212 | EXPORT_SYMBOL(vga_switcheroo_unregister_client); |
@@ -159,29 +214,29 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_client); | |||
159 | void vga_switcheroo_client_fb_set(struct pci_dev *pdev, | 214 | void vga_switcheroo_client_fb_set(struct pci_dev *pdev, |
160 | struct fb_info *info) | 215 | struct fb_info *info) |
161 | { | 216 | { |
162 | int i; | 217 | struct vga_switcheroo_client *client; |
163 | 218 | ||
164 | mutex_lock(&vgasr_mutex); | 219 | mutex_lock(&vgasr_mutex); |
165 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 220 | client = find_client_from_pci(&vgasr_priv.clients, pdev); |
166 | if (vgasr_priv.clients[i].pdev == pdev) { | 221 | if (client) |
167 | vgasr_priv.clients[i].fb_info = info; | 222 | client->fb_info = info; |
168 | break; | ||
169 | } | ||
170 | } | ||
171 | mutex_unlock(&vgasr_mutex); | 223 | mutex_unlock(&vgasr_mutex); |
172 | } | 224 | } |
173 | EXPORT_SYMBOL(vga_switcheroo_client_fb_set); | 225 | EXPORT_SYMBOL(vga_switcheroo_client_fb_set); |
174 | 226 | ||
175 | static int vga_switcheroo_show(struct seq_file *m, void *v) | 227 | static int vga_switcheroo_show(struct seq_file *m, void *v) |
176 | { | 228 | { |
177 | int i; | 229 | struct vga_switcheroo_client *client; |
230 | int i = 0; | ||
178 | mutex_lock(&vgasr_mutex); | 231 | mutex_lock(&vgasr_mutex); |
179 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 232 | list_for_each_entry(client, &vgasr_priv.clients, list) { |
180 | seq_printf(m, "%d:%s:%c:%s:%s\n", i, | 233 | seq_printf(m, "%d:%s%s:%c:%s:%s\n", i, |
181 | vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", | 234 | client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", |
182 | vgasr_priv.clients[i].active ? '+' : ' ', | 235 | client_is_vga(client) ? "" : "-Audio", |
183 | vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off", | 236 | client->active ? '+' : ' ', |
184 | pci_name(vgasr_priv.clients[i].pdev)); | 237 | client->pwr_state ? "Pwr" : "Off", |
238 | pci_name(client->pdev)); | ||
239 | i++; | ||
185 | } | 240 | } |
186 | mutex_unlock(&vgasr_mutex); | 241 | mutex_unlock(&vgasr_mutex); |
187 | return 0; | 242 | return 0; |
@@ -197,7 +252,7 @@ static int vga_switchon(struct vga_switcheroo_client *client) | |||
197 | if (vgasr_priv.handler->power_state) | 252 | if (vgasr_priv.handler->power_state) |
198 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); | 253 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); |
199 | /* call the driver callback to turn on device */ | 254 | /* call the driver callback to turn on device */ |
200 | client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); | 255 | client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); |
201 | client->pwr_state = VGA_SWITCHEROO_ON; | 256 | client->pwr_state = VGA_SWITCHEROO_ON; |
202 | return 0; | 257 | return 0; |
203 | } | 258 | } |
@@ -205,34 +260,39 @@ static int vga_switchon(struct vga_switcheroo_client *client) | |||
205 | static int vga_switchoff(struct vga_switcheroo_client *client) | 260 | static int vga_switchoff(struct vga_switcheroo_client *client) |
206 | { | 261 | { |
207 | /* call the driver callback to turn off device */ | 262 | /* call the driver callback to turn off device */ |
208 | client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); | 263 | client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); |
209 | if (vgasr_priv.handler->power_state) | 264 | if (vgasr_priv.handler->power_state) |
210 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); | 265 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); |
211 | client->pwr_state = VGA_SWITCHEROO_OFF; | 266 | client->pwr_state = VGA_SWITCHEROO_OFF; |
212 | return 0; | 267 | return 0; |
213 | } | 268 | } |
214 | 269 | ||
270 | static 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 | |||
215 | /* stage one happens before delay */ | 281 | /* stage one happens before delay */ |
216 | static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) | 282 | static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) |
217 | { | 283 | { |
218 | int i; | 284 | struct vga_switcheroo_client *active; |
219 | struct vga_switcheroo_client *active = NULL; | ||
220 | 285 | ||
221 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 286 | active = find_active_client(&vgasr_priv.clients); |
222 | if (vgasr_priv.clients[i].active == true) { | ||
223 | active = &vgasr_priv.clients[i]; | ||
224 | break; | ||
225 | } | ||
226 | } | ||
227 | if (!active) | 287 | if (!active) |
228 | return 0; | 288 | return 0; |
229 | 289 | ||
230 | if (new_client->pwr_state == VGA_SWITCHEROO_OFF) | 290 | if (new_client->pwr_state == VGA_SWITCHEROO_OFF) |
231 | vga_switchon(new_client); | 291 | vga_switchon(new_client); |
232 | 292 | ||
233 | /* swap shadow resource to denote boot VGA device has changed so X starts on new device */ | 293 | vga_set_default_device(new_client->pdev); |
234 | active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW; | 294 | set_audio_state(new_client->id, VGA_SWITCHEROO_ON); |
235 | new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; | 295 | |
236 | return 0; | 296 | return 0; |
237 | } | 297 | } |
238 | 298 | ||
@@ -240,15 +300,9 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) | |||
240 | static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) | 300 | static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) |
241 | { | 301 | { |
242 | int ret; | 302 | int ret; |
243 | int i; | 303 | struct vga_switcheroo_client *active; |
244 | struct vga_switcheroo_client *active = NULL; | ||
245 | 304 | ||
246 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 305 | active = find_active_client(&vgasr_priv.clients); |
247 | if (vgasr_priv.clients[i].active == true) { | ||
248 | active = &vgasr_priv.clients[i]; | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | if (!active) | 306 | if (!active) |
253 | return 0; | 307 | return 0; |
254 | 308 | ||
@@ -264,8 +318,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) | |||
264 | if (ret) | 318 | if (ret) |
265 | return ret; | 319 | return ret; |
266 | 320 | ||
267 | if (new_client->reprobe) | 321 | if (new_client->ops->reprobe) |
268 | new_client->reprobe(new_client->pdev); | 322 | new_client->ops->reprobe(new_client->pdev); |
323 | |||
324 | set_audio_state(active->id, VGA_SWITCHEROO_OFF); | ||
269 | 325 | ||
270 | if (active->pwr_state == VGA_SWITCHEROO_ON) | 326 | if (active->pwr_state == VGA_SWITCHEROO_ON) |
271 | vga_switchoff(active); | 327 | vga_switchoff(active); |
@@ -274,13 +330,26 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) | |||
274 | return 0; | 330 | return 0; |
275 | } | 331 | } |
276 | 332 | ||
333 | static bool check_can_switch(void) | ||
334 | { | ||
335 | struct vga_switcheroo_client *client; | ||
336 | |||
337 | list_for_each_entry(client, &vgasr_priv.clients, list) { | ||
338 | if (!client->ops->can_switch(client->pdev)) { | ||
339 | printk(KERN_ERR "vga_switcheroo: client %x refused switch\n", client->id); | ||
340 | return false; | ||
341 | } | ||
342 | } | ||
343 | return true; | ||
344 | } | ||
345 | |||
277 | static ssize_t | 346 | static ssize_t |
278 | vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | 347 | vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, |
279 | size_t cnt, loff_t *ppos) | 348 | size_t cnt, loff_t *ppos) |
280 | { | 349 | { |
281 | char usercmd[64]; | 350 | char usercmd[64]; |
282 | const char *pdev_name; | 351 | const char *pdev_name; |
283 | int i, ret; | 352 | int ret; |
284 | bool delay = false, can_switch; | 353 | bool delay = false, can_switch; |
285 | bool just_mux = false; | 354 | bool just_mux = false; |
286 | int client_id = -1; | 355 | int client_id = -1; |
@@ -301,21 +370,21 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
301 | 370 | ||
302 | /* pwr off the device not in use */ | 371 | /* pwr off the device not in use */ |
303 | if (strncmp(usercmd, "OFF", 3) == 0) { | 372 | if (strncmp(usercmd, "OFF", 3) == 0) { |
304 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 373 | list_for_each_entry(client, &vgasr_priv.clients, list) { |
305 | if (vgasr_priv.clients[i].active) | 374 | if (client->active) |
306 | continue; | 375 | continue; |
307 | if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_ON) | 376 | if (client->pwr_state == VGA_SWITCHEROO_ON) |
308 | vga_switchoff(&vgasr_priv.clients[i]); | 377 | vga_switchoff(client); |
309 | } | 378 | } |
310 | goto out; | 379 | goto out; |
311 | } | 380 | } |
312 | /* pwr on the device not in use */ | 381 | /* pwr on the device not in use */ |
313 | if (strncmp(usercmd, "ON", 2) == 0) { | 382 | if (strncmp(usercmd, "ON", 2) == 0) { |
314 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 383 | list_for_each_entry(client, &vgasr_priv.clients, list) { |
315 | if (vgasr_priv.clients[i].active) | 384 | if (client->active) |
316 | continue; | 385 | continue; |
317 | if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_OFF) | 386 | if (client->pwr_state == VGA_SWITCHEROO_OFF) |
318 | vga_switchon(&vgasr_priv.clients[i]); | 387 | vga_switchon(client); |
319 | } | 388 | } |
320 | goto out; | 389 | goto out; |
321 | } | 390 | } |
@@ -348,13 +417,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
348 | 417 | ||
349 | if (client_id == -1) | 418 | if (client_id == -1) |
350 | goto out; | 419 | goto out; |
351 | 420 | client = find_client_from_id(&vgasr_priv.clients, client_id); | |
352 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 421 | if (!client) |
353 | if (vgasr_priv.clients[i].id == client_id) { | 422 | goto out; |
354 | client = &vgasr_priv.clients[i]; | ||
355 | break; | ||
356 | } | ||
357 | } | ||
358 | 423 | ||
359 | vgasr_priv.delayed_switch_active = false; | 424 | vgasr_priv.delayed_switch_active = false; |
360 | 425 | ||
@@ -363,23 +428,16 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
363 | goto out; | 428 | goto out; |
364 | } | 429 | } |
365 | 430 | ||
366 | if (client->active == true) | 431 | if (client->active) |
367 | goto out; | 432 | goto out; |
368 | 433 | ||
369 | /* okay we want a switch - test if devices are willing to switch */ | 434 | /* okay we want a switch - test if devices are willing to switch */ |
370 | can_switch = true; | 435 | can_switch = check_can_switch(); |
371 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | ||
372 | can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev); | ||
373 | if (can_switch == false) { | ||
374 | printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i); | ||
375 | break; | ||
376 | } | ||
377 | } | ||
378 | 436 | ||
379 | if (can_switch == false && delay == false) | 437 | if (can_switch == false && delay == false) |
380 | goto out; | 438 | goto out; |
381 | 439 | ||
382 | if (can_switch == true) { | 440 | if (can_switch) { |
383 | pdev_name = pci_name(client->pdev); | 441 | pdev_name = pci_name(client->pdev); |
384 | ret = vga_switchto_stage1(client); | 442 | ret = vga_switchto_stage1(client); |
385 | if (ret) | 443 | if (ret) |
@@ -451,10 +509,8 @@ fail: | |||
451 | 509 | ||
452 | int vga_switcheroo_process_delayed_switch(void) | 510 | int vga_switcheroo_process_delayed_switch(void) |
453 | { | 511 | { |
454 | struct vga_switcheroo_client *client = NULL; | 512 | struct vga_switcheroo_client *client; |
455 | const char *pdev_name; | 513 | const char *pdev_name; |
456 | bool can_switch = true; | ||
457 | int i; | ||
458 | int ret; | 514 | int ret; |
459 | int err = -EINVAL; | 515 | int err = -EINVAL; |
460 | 516 | ||
@@ -464,17 +520,9 @@ int vga_switcheroo_process_delayed_switch(void) | |||
464 | 520 | ||
465 | printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id); | 521 | printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id); |
466 | 522 | ||
467 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 523 | client = find_client_from_id(&vgasr_priv.clients, |
468 | if (vgasr_priv.clients[i].id == vgasr_priv.delayed_client_id) | 524 | vgasr_priv.delayed_client_id); |
469 | client = &vgasr_priv.clients[i]; | 525 | if (!client || !check_can_switch()) |
470 | can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev); | ||
471 | if (can_switch == false) { | ||
472 | printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i); | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | if (can_switch == false || client == NULL) | ||
478 | goto err; | 526 | goto err; |
479 | 527 | ||
480 | pdev_name = pci_name(client->pdev); | 528 | pdev_name = pci_name(client->pdev); |