aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorKristen Accardi <kristen.c.accardi@intel.com>2006-06-28 03:08:06 -0400
committerLen Brown <len.brown@intel.com>2006-06-28 03:08:06 -0400
commit4e8662bbd680c54496189ac68f398e847f3ca374 (patch)
tree8f9a0be5098b206025cd63fe965ccc37c922753e /drivers/pci
parenta5e1b94008f2a96abf4a0c0371a55a56b320c13e (diff)
ACPIPHP: use ACPI dock driver
Modify the acpiphp driver to use the ACPI dock driver for dock notifications. Only load the acpiphp driver if we find we have pci dock devices. Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/Makefile3
-rw-r--r--drivers/pci/hotplug/acpiphp.h35
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c19
-rw-r--r--drivers/pci/hotplug/acpiphp_dock.c438
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c111
5 files changed, 87 insertions, 519 deletions
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 421cfffb1756..34a1891191fd 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -40,8 +40,7 @@ ibmphp-objs := ibmphp_core.o \
40 ibmphp_hpc.o 40 ibmphp_hpc.o
41 41
42acpiphp-objs := acpiphp_core.o \ 42acpiphp-objs := acpiphp_core.o \
43 acpiphp_glue.o \ 43 acpiphp_glue.o
44 acpiphp_dock.o
45 44
46rpaphp-objs := rpaphp_core.o \ 45rpaphp-objs := rpaphp_core.o \
47 rpaphp_pci.o \ 46 rpaphp_pci.o \
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 17a93f890dba..e8fddf943281 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -130,7 +130,7 @@ struct acpiphp_func {
130 130
131 struct list_head sibling; 131 struct list_head sibling;
132 struct pci_dev *pci_dev; 132 struct pci_dev *pci_dev;
133 133 struct notifier_block nb;
134 acpi_handle handle; 134 acpi_handle handle;
135 135
136 u8 function; /* pci function# */ 136 u8 function; /* pci function# */
@@ -151,24 +151,6 @@ struct acpiphp_attention_info
151}; 151};
152 152
153 153
154struct dependent_device {
155 struct list_head device_list;
156 struct list_head pci_list;
157 acpi_handle handle;
158 struct acpiphp_func *func;
159};
160
161
162struct acpiphp_dock_station {
163 acpi_handle handle;
164 u32 last_dock_time;
165 u32 flags;
166 struct acpiphp_func *dock_bridge;
167 struct list_head dependent_devices;
168 struct list_head pci_dependent_devices;
169};
170
171
172/* PCI bus bridge HID */ 154/* PCI bus bridge HID */
173#define ACPI_PCI_HOST_HID "PNP0A03" 155#define ACPI_PCI_HOST_HID "PNP0A03"
174 156
@@ -207,11 +189,6 @@ struct acpiphp_dock_station {
207#define FUNC_HAS_PS2 (0x00000040) 189#define FUNC_HAS_PS2 (0x00000040)
208#define FUNC_HAS_PS3 (0x00000080) 190#define FUNC_HAS_PS3 (0x00000080)
209#define FUNC_HAS_DCK (0x00000100) 191#define FUNC_HAS_DCK (0x00000100)
210#define FUNC_IS_DD (0x00000200)
211
212/* dock station flags */
213#define DOCK_DOCKING (0x00000001)
214#define DOCK_HAS_BRIDGE (0x00000002)
215 192
216/* function prototypes */ 193/* function prototypes */
217 194
@@ -236,16 +213,6 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
236extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); 213extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
237extern u32 acpiphp_get_address (struct acpiphp_slot *slot); 214extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
238 215
239/* acpiphp_dock.c */
240extern int find_dock_station(void);
241extern void remove_dock_station(void);
242extern void add_dependent_device(struct dependent_device *new_dd);
243extern void add_pci_dependent_device(struct dependent_device *new_dd);
244extern struct dependent_device *get_dependent_device(acpi_handle handle);
245extern int is_dependent_device(acpi_handle handle);
246extern int detect_dependent_devices(acpi_handle *bridge_handle);
247extern struct dependent_device *alloc_dependent_device(acpi_handle handle);
248
249/* variables */ 216/* variables */
250extern int acpiphp_debug; 217extern int acpiphp_debug;
251 218
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 4f1b0da8e47e..34de5697983d 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -416,27 +416,12 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
416 416
417static int __init acpiphp_init(void) 417static int __init acpiphp_init(void)
418{ 418{
419 int retval;
420 int docking_station;
421
422 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 419 info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
423 420
424 acpiphp_debug = debug; 421 acpiphp_debug = debug;
425 422
426 docking_station = find_dock_station();
427
428 /* read all the ACPI info from the system */ 423 /* read all the ACPI info from the system */
429 retval = init_acpi(); 424 return init_acpi();
430
431 /* if we have found a docking station, we should
432 * go ahead and load even if init_acpi has found
433 * no slots. This handles the case when the _DCK
434 * method not defined under the actual dock bridge
435 */
436 if (docking_station)
437 return 0;
438 else
439 return retval;
440} 425}
441 426
442 427
@@ -444,8 +429,6 @@ static void __exit acpiphp_exit(void)
444{ 429{
445 /* deallocate internal data structures etc. */ 430 /* deallocate internal data structures etc. */
446 acpiphp_glue_exit(); 431 acpiphp_glue_exit();
447
448 remove_dock_station();
449} 432}
450 433
451module_init(acpiphp_init); 434module_init(acpiphp_init);
diff --git a/drivers/pci/hotplug/acpiphp_dock.c b/drivers/pci/hotplug/acpiphp_dock.c
deleted file mode 100644
index 4f1aaf128312..000000000000
--- a/drivers/pci/hotplug/acpiphp_dock.c
+++ /dev/null
@@ -1,438 +0,0 @@
1/*
2 * ACPI PCI HotPlug dock functions to ACPI CA subsystem
3 *
4 * Copyright (C) 2006 Kristen Carlson Accardi (kristen.c.accardi@intel.com)
5 * Copyright (C) 2006 Intel Corporation
6 *
7 * All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
17 * NON INFRINGEMENT. See the GNU General Public License for more
18 * details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * Send feedback to <kristen.c.accardi@intel.com>
25 *
26 */
27#include <linux/init.h>
28#include <linux/module.h>
29
30#include <linux/kernel.h>
31#include <linux/pci.h>
32#include <linux/smp_lock.h>
33#include <linux/mutex.h>
34
35#include "../pci.h"
36#include "pci_hotplug.h"
37#include "acpiphp.h"
38
39static struct acpiphp_dock_station *ds;
40#define MY_NAME "acpiphp_dock"
41
42
43int is_dependent_device(acpi_handle handle)
44{
45 return (get_dependent_device(handle) ? 1 : 0);
46}
47
48
49static acpi_status
50find_dependent_device(acpi_handle handle, u32 lvl, void *context, void **rv)
51{
52 int *count = (int *)context;
53
54 if (is_dependent_device(handle)) {
55 (*count)++;
56 return AE_CTRL_TERMINATE;
57 } else {
58 return AE_OK;
59 }
60}
61
62
63
64
65void add_dependent_device(struct dependent_device *new_dd)
66{
67 list_add_tail(&new_dd->device_list, &ds->dependent_devices);
68}
69
70
71void add_pci_dependent_device(struct dependent_device *new_dd)
72{
73 list_add_tail(&new_dd->pci_list, &ds->pci_dependent_devices);
74}
75
76
77
78struct dependent_device * get_dependent_device(acpi_handle handle)
79{
80 struct dependent_device *dd;
81
82 if (!ds)
83 return NULL;
84
85 list_for_each_entry(dd, &ds->dependent_devices, device_list) {
86 if (handle == dd->handle)
87 return dd;
88 }
89 return NULL;
90}
91
92
93
94struct dependent_device *alloc_dependent_device(acpi_handle handle)
95{
96 struct dependent_device *dd;
97
98 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
99 if (dd) {
100 INIT_LIST_HEAD(&dd->pci_list);
101 INIT_LIST_HEAD(&dd->device_list);
102 dd->handle = handle;
103 }
104 return dd;
105}
106
107
108
109static int is_dock(acpi_handle handle)
110{
111 acpi_status status;
112 acpi_handle tmp;
113
114 status = acpi_get_handle(handle, "_DCK", &tmp);
115 if (ACPI_FAILURE(status)) {
116 return 0;
117 }
118 return 1;
119}
120
121
122
123static int dock_present(void)
124{
125 unsigned long sta;
126 acpi_status status;
127
128 if (ds) {
129 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
130 if (ACPI_SUCCESS(status) && sta)
131 return 1;
132 }
133 return 0;
134}
135
136
137
138static void eject_dock(void)
139{
140 struct acpi_object_list arg_list;
141 union acpi_object arg;
142
143 arg_list.count = 1;
144 arg_list.pointer = &arg;
145 arg.type = ACPI_TYPE_INTEGER;
146 arg.integer.value = 1;
147
148 if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
149 &arg_list, NULL)) || dock_present())
150 warn("%s: failed to eject dock!\n", __FUNCTION__);
151
152 return;
153}
154
155
156
157
158static acpi_status handle_dock(int dock)
159{
160 acpi_status status;
161 struct acpi_object_list arg_list;
162 union acpi_object arg;
163 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
164
165 dbg("%s: %s\n", __FUNCTION__, dock ? "docking" : "undocking");
166
167 /* _DCK method has one argument */
168 arg_list.count = 1;
169 arg_list.pointer = &arg;
170 arg.type = ACPI_TYPE_INTEGER;
171 arg.integer.value = dock;
172 status = acpi_evaluate_object(ds->handle, "_DCK",
173 &arg_list, &buffer);
174 if (ACPI_FAILURE(status))
175 err("%s: failed to execute _DCK\n", __FUNCTION__);
176 acpi_os_free(buffer.pointer);
177
178 return status;
179}
180
181
182
183static inline void dock(void)
184{
185 handle_dock(1);
186}
187
188
189
190static inline void undock(void)
191{
192 handle_dock(0);
193}
194
195
196
197/*
198 * the _DCK method can do funny things... and sometimes not
199 * hah-hah funny.
200 *
201 * TBD - figure out a way to only call fixups for
202 * systems that require them.
203 */
204static void post_dock_fixups(void)
205{
206 struct pci_bus *bus;
207 u32 buses;
208 struct dependent_device *dd;
209
210 list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) {
211 bus = dd->func->slot->bridge->pci_bus;
212
213 /* fixup bad _DCK function that rewrites
214 * secondary bridge on slot
215 */
216 pci_read_config_dword(bus->self,
217 PCI_PRIMARY_BUS,
218 &buses);
219
220 if (((buses >> 8) & 0xff) != bus->secondary) {
221 buses = (buses & 0xff000000)
222 | ((unsigned int)(bus->primary) << 0)
223 | ((unsigned int)(bus->secondary) << 8)
224 | ((unsigned int)(bus->subordinate) << 16);
225 pci_write_config_dword(bus->self,
226 PCI_PRIMARY_BUS,
227 buses);
228 }
229 }
230}
231
232
233
234static void hotplug_pci(u32 type)
235{
236 struct dependent_device *dd;
237
238 list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list)
239 handle_hotplug_event_func(dd->handle, type, dd->func);
240}
241
242
243
244static inline void begin_dock(void)
245{
246 ds->flags |= DOCK_DOCKING;
247}
248
249
250static inline void complete_dock(void)
251{
252 ds->flags &= ~(DOCK_DOCKING);
253 ds->last_dock_time = jiffies;
254}
255
256
257static int dock_in_progress(void)
258{
259 if (ds->flags & DOCK_DOCKING ||
260 ds->last_dock_time == jiffies) {
261 dbg("dock in progress\n");
262 return 1;
263 }
264 return 0;
265}
266
267
268
269static void
270handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
271{
272 dbg("%s: enter\n", __FUNCTION__);
273
274 switch (type) {
275 case ACPI_NOTIFY_BUS_CHECK:
276 dbg("BUS Check\n");
277 if (!dock_in_progress() && dock_present()) {
278 begin_dock();
279 dock();
280 if (!dock_present()) {
281 err("Unable to dock!\n");
282 break;
283 }
284 post_dock_fixups();
285 hotplug_pci(type);
286 complete_dock();
287 }
288 break;
289 case ACPI_NOTIFY_EJECT_REQUEST:
290 dbg("EJECT request\n");
291 if (!dock_in_progress() && dock_present()) {
292 hotplug_pci(type);
293 undock();
294 eject_dock();
295 if (dock_present())
296 err("Unable to undock!\n");
297 }
298 break;
299 }
300}
301
302
303
304
305static acpi_status
306find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv)
307{
308 acpi_status status;
309 acpi_handle tmp;
310 acpi_handle dck_handle = (acpi_handle) context;
311 char objname[64];
312 struct acpi_buffer buffer = { .length = sizeof(objname),
313 .pointer = objname };
314 struct acpi_buffer ejd_buffer = {ACPI_ALLOCATE_BUFFER, NULL};
315 union acpi_object *ejd_obj;
316
317 status = acpi_get_handle(handle, "_EJD", &tmp);
318 if (ACPI_FAILURE(status))
319 return AE_OK;
320
321 /* make sure we are dependent on the dock device,
322 * by executing the _EJD method, then getting a handle
323 * to the device referenced by that name. If that
324 * device handle is the same handle as the dock station
325 * handle, then we are a device dependent on the dock station
326 */
327 acpi_get_name(dck_handle, ACPI_FULL_PATHNAME, &buffer);
328 status = acpi_evaluate_object(handle, "_EJD", NULL, &ejd_buffer);
329 if (ACPI_FAILURE(status)) {
330 err("Unable to execute _EJD!\n");
331 goto find_ejd_out;
332 }
333 ejd_obj = ejd_buffer.pointer;
334 status = acpi_get_handle(NULL, ejd_obj->string.pointer, &tmp);
335 if (ACPI_FAILURE(status))
336 goto find_ejd_out;
337
338 if (tmp == dck_handle) {
339 struct dependent_device *dd;
340 dbg("%s: found device dependent on dock\n", __FUNCTION__);
341 dd = alloc_dependent_device(handle);
342 if (!dd) {
343 err("Can't allocate memory for dependent device!\n");
344 goto find_ejd_out;
345 }
346 add_dependent_device(dd);
347 }
348
349find_ejd_out:
350 acpi_os_free(ejd_buffer.pointer);
351 return AE_OK;
352}
353
354
355
356int detect_dependent_devices(acpi_handle *bridge_handle)
357{
358 acpi_status status;
359 int count;
360
361 count = 0;
362
363 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
364 (u32)1, find_dependent_device,
365 (void *)&count, NULL);
366
367 return count;
368}
369
370
371
372
373
374static acpi_status
375find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
376{
377 int *count = (int *)context;
378
379 if (is_dock(handle)) {
380 dbg("%s: found dock\n", __FUNCTION__);
381 ds = kzalloc(sizeof(*ds), GFP_KERNEL);
382 ds->handle = handle;
383 INIT_LIST_HEAD(&ds->dependent_devices);
384 INIT_LIST_HEAD(&ds->pci_dependent_devices);
385
386 /* look for devices dependent on dock station */
387 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
388 ACPI_UINT32_MAX, find_dock_ejd, handle, NULL);
389
390 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
391 handle_hotplug_event_dock, ds);
392 (*count)++;
393 }
394
395 return AE_OK;
396}
397
398
399
400
401int find_dock_station(void)
402{
403 int num = 0;
404
405 ds = NULL;
406
407 /* start from the root object, because some laptops define
408 * _DCK methods outside the scope of PCI (IBM x-series laptop)
409 */
410 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
411 ACPI_UINT32_MAX, find_dock, &num, NULL);
412
413 return num;
414}
415
416
417
418void remove_dock_station(void)
419{
420 struct dependent_device *dd, *tmp;
421 if (ds) {
422 if (ACPI_FAILURE(acpi_remove_notify_handler(ds->handle,
423 ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
424 err("failed to remove dock notify handler\n");
425
426 /* free all dependent devices */
427 list_for_each_entry_safe(dd, tmp, &ds->dependent_devices,
428 device_list)
429 kfree(dd);
430
431 /* no need to touch the pci_dependent_device list,
432 * cause all memory was freed above
433 */
434 kfree(ds);
435 }
436}
437
438
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index d370f999782e..faf7eed5d963 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -116,6 +116,59 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
116 } 116 }
117} 117}
118 118
119/* callback routine to check for the existance of a pci dock device */
120static acpi_status
121is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
122{
123 int *count = (int *)context;
124
125 if (is_dock_device(handle)) {
126 (*count)++;
127 return AE_CTRL_TERMINATE;
128 } else {
129 return AE_OK;
130 }
131}
132
133
134
135
136/*
137 * the _DCK method can do funny things... and sometimes not
138 * hah-hah funny.
139 *
140 * TBD - figure out a way to only call fixups for
141 * systems that require them.
142 */
143static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
144 void *v)
145{
146 struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
147 struct pci_bus *bus = func->slot->bridge->pci_bus;
148 u32 buses;
149
150 if (!bus->self)
151 return NOTIFY_OK;
152
153 /* fixup bad _DCK function that rewrites
154 * secondary bridge on slot
155 */
156 pci_read_config_dword(bus->self,
157 PCI_PRIMARY_BUS,
158 &buses);
159
160 if (((buses >> 8) & 0xff) != bus->secondary) {
161 buses = (buses & 0xff000000)
162 | ((unsigned int)(bus->primary) << 0)
163 | ((unsigned int)(bus->secondary) << 8)
164 | ((unsigned int)(bus->subordinate) << 16);
165 pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
166 }
167 return NOTIFY_OK;
168}
169
170
171
119 172
120/* callback routine to register each ACPI PCI slot object */ 173/* callback routine to register each ACPI PCI slot object */
121static acpi_status 174static acpi_status
@@ -124,7 +177,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
124 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 177 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
125 struct acpiphp_slot *slot; 178 struct acpiphp_slot *slot;
126 struct acpiphp_func *newfunc; 179 struct acpiphp_func *newfunc;
127 struct dependent_device *dd;
128 acpi_handle tmp; 180 acpi_handle tmp;
129 acpi_status status = AE_OK; 181 acpi_status status = AE_OK;
130 unsigned long adr, sun; 182 unsigned long adr, sun;
@@ -137,7 +189,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
137 189
138 status = acpi_get_handle(handle, "_EJ0", &tmp); 190 status = acpi_get_handle(handle, "_EJ0", &tmp);
139 191
140 if (ACPI_FAILURE(status) && !(is_dependent_device(handle))) 192 if (ACPI_FAILURE(status) && !(is_dock_device(handle)))
141 return AE_OK; 193 return AE_OK;
142 194
143 device = (adr >> 16) & 0xffff; 195 device = (adr >> 16) & 0xffff;
@@ -162,18 +214,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
162 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 214 if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
163 newfunc->flags |= FUNC_HAS_PS3; 215 newfunc->flags |= FUNC_HAS_PS3;
164 216
165 if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) { 217 if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
166 newfunc->flags |= FUNC_HAS_DCK; 218 newfunc->flags |= FUNC_HAS_DCK;
167 /* add to devices dependent on dock station,
168 * because this may actually be the dock bridge
169 */
170 dd = alloc_dependent_device(handle);
171 if (!dd)
172 err("Can't allocate memory for "
173 "new dependent device!\n");
174 else
175 add_dependent_device(dd);
176 }
177 219
178 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 220 status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
179 if (ACPI_FAILURE(status)) 221 if (ACPI_FAILURE(status))
@@ -225,20 +267,23 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
225 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 267 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
226 } 268 }
227 269
228 /* if this is a device dependent on a dock station, 270 if (is_dock_device(handle)) {
229 * associate the acpiphp_func to the dependent_device 271 /* we don't want to call this device's _EJ0
230 * struct. 272 * because we want the dock notify handler
231 */ 273 * to call it after it calls _DCK
232 if ((dd = get_dependent_device(handle))) {
233 newfunc->flags |= FUNC_IS_DD;
234 /*
235 * we don't want any devices which is dependent
236 * on the dock to have it's _EJ0 method executed.
237 * because we need to run _DCK first.
238 */ 274 */
239 newfunc->flags &= ~FUNC_HAS_EJ0; 275 newfunc->flags &= ~FUNC_HAS_EJ0;
240 dd->func = newfunc; 276 if (register_hotplug_dock_device(handle,
241 add_pci_dependent_device(dd); 277 handle_hotplug_event_func, newfunc))
278 dbg("failed to register dock device\n");
279
280 /* we need to be notified when dock events happen
281 * outside of the hotplug operation, since we may
282 * need to do fixups before we can hotplug.
283 */
284 newfunc->nb.notifier_call = post_dock_fixups;
285 if (register_dock_notifier(&newfunc->nb))
286 dbg("failed to register a dock notifier");
242 } 287 }
243 288
244 /* install notify handler */ 289 /* install notify handler */
@@ -277,6 +322,15 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle)
277 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, 322 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
278 is_ejectable_slot, (void *)&count, NULL); 323 is_ejectable_slot, (void *)&count, NULL);
279 324
325 /*
326 * we also need to add this bridge if there is a dock bridge or
327 * other pci device on a dock station (removable)
328 */
329 if (!count)
330 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
331 (u32)1, is_pci_dock_device, (void *)&count,
332 NULL);
333
280 return count; 334 return count;
281} 335}
282 336
@@ -487,8 +541,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
487 goto out; 541 goto out;
488 542
489 /* check if this bridge has ejectable slots */ 543 /* check if this bridge has ejectable slots */
490 if ((detect_ejectable_slots(handle) > 0) || 544 if ((detect_ejectable_slots(handle) > 0)) {
491 (detect_dependent_devices(handle) > 0)) {
492 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 545 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
493 add_p2p_bridge(handle, dev); 546 add_p2p_bridge(handle, dev);
494 } 547 }
@@ -605,6 +658,10 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
605 list_for_each_safe (list, tmp, &slot->funcs) { 658 list_for_each_safe (list, tmp, &slot->funcs) {
606 struct acpiphp_func *func; 659 struct acpiphp_func *func;
607 func = list_entry(list, struct acpiphp_func, sibling); 660 func = list_entry(list, struct acpiphp_func, sibling);
661 if (is_dock_device(func->handle)) {
662 unregister_hotplug_dock_device(func->handle);
663 unregister_dock_notifier(&func->nb);
664 }
608 if (!(func->flags & FUNC_HAS_DCK)) { 665 if (!(func->flags & FUNC_HAS_DCK)) {
609 status = acpi_remove_notify_handler(func->handle, 666 status = acpi_remove_notify_handler(func->handle,
610 ACPI_SYSTEM_NOTIFY, 667 ACPI_SYSTEM_NOTIFY,