On Sat, 2006-01-21 at 13:10 +0100, Pavel Machek wrote:
<snip>
> 
> Oopsen seems to be called because add_p2p_bridge is never called. I
> think it should be called for this device:
> 
> 0000:00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 81)
> 
> --- clean-mm//drivers/pci/hotplug/acpiphp_glue.c      2006-01-21 
> 11:38:51.000000000 +0100
> +++ linux-mm/drivers/pci/hotplug/acpiphp_glue.c       2006-01-21 
> 12:53:28.000000000 +0100
> @@ -454,16 +457,22 @@
>               return AE_OK;
>       }
>  
> +     printk("ADR ok\n");
> +
>       device = (tmp >> 16) & 0xffff;
>       function = tmp & 0xffff;
>  
>       dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
>  
> +     printk("device, function = %lx\n", tmp);
> +
>       if (!dev || !dev->subordinate)
>               goto out;
>  
> +     printk("detect slots\n");
> +
>       /* check if this bridge has ejectable slots */
> -     if (detect_ejectable_slots(handle) > 0) {
> +     if ((tmp == 0x1e0000) || (detect_ejectable_slots(handle) > 0)) {
>               dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
>               add_p2p_bridge(handle, dev);
>       }
> 
> ...but then bridge->slots is still empty. I tried forcing
> is_ejectable(), but then I get:
> 
> Jan 21 13:09:52 amd kernel: acpiphp: ACPI Hot Plug PCI Controller
> Driver version: 0.5
> Jan 21 13:09:53 amd kernel: add_bridge
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1f0000
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 10000
> Jan 21 13:09:53 amd kernel: detect slots
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1e0000
> Jan 21 13:09:53 amd kernel: detect slots
> Jan 21 13:09:53 amd kernel: acpiphp_glue: found PCI-to-PCI bridge at
> PCI 0000:00:1e.0
> Jan 21 13:09:53 amd kernel: add_p2p_bridge
> Jan 21 13:09:53 amd kernel: acpiphp_glue: _HPP evaluation failed
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1f0001
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0000
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0001
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0002
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1d0007
> Jan 21 13:09:53 amd kernel: find_p2p_bridge
> Jan 21 13:09:53 amd kernel: ADR ok
> Jan 21 13:09:53 amd kernel: device, function = 1f0006
> Jan 21 13:09:53 amd kernel: acpiphp_glue: Bus 0000:02 has 0 slots
> Jan 21 13:09:53 amd kernel: acpiphp_glue: Total 0 slots
> Jan 21 13:10:05 amd pam_limits[1345]: wrong limit value 'unlimited'
> 
>                                                               Pavel


Well, let's back up a bit.  I see a few things wrong.  Starting with
just the basics, it doesn't seem like we have even found your _DCK
method, otherwise find_num_slots should have reported 1.  If we had been
able to find the dock bridge, then adding the p2p bridge would have
worked as well.  Let's debug this problem first - Can you please try
this patch, making sure to load the module with debugging enabled:

modprobe acpiphp debug=1

and then send me the output of dmesg -s 10000?  Thanks for helping me
debug, I appreciate it.  This patch just adds some extra debugging info
to the code path that I would expect to be taken while trying to find
your _DCK method.  Other than that, it is unchanged.

Kristen

 drivers/pci/hotplug/acpiphp.h      |   11 +
 drivers/pci/hotplug/acpiphp_glue.c |  366 +++++++++++++++++++++++++++----------
 2 files changed, 284 insertions(+), 93 deletions(-)

--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp.h
@@ -148,6 +148,17 @@ struct acpiphp_func {
        u32             flags;          /* see below */
 };
 
+
+struct acpiphp_dock_bridge {
+       acpi_handle dock_bridge_handle;
+       acpi_handle dck_handle;
+       struct acpiphp_func *func;
+       struct acpiphp_slot *slot;
+       u32 last_dock_time;
+       u32 flags;
+};
+
+
 /**
  * struct acpiphp_attention_info - device specific attention registration
  *
--- linux-2.6.16-rc1.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-2.6.16-rc1/drivers/pci/hotplug/acpiphp_glue.c
@@ -53,15 +53,14 @@
 #include "acpiphp.h"
 
 static LIST_HEAD(bridge_list);
+static struct acpiphp_dock_bridge dock_bridge;
 
 #define MY_NAME "acpiphp_glue"
-static struct work_struct dock_task;
 static int enable_device(struct acpiphp_slot *slot);
 static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void handle_hotplug_event_func (acpi_handle, u32, void *);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
-static void dock(void *data);
 static unsigned int get_slot_status(struct acpiphp_slot *slot);
 
 /*
@@ -104,13 +103,26 @@ static int is_ejectable(acpi_handle hand
 }
 
 
+
+static int is_dock(acpi_handle handle)
+{
+       acpi_status status;
+       acpi_handle tmp;
+
+       status = acpi_get_handle(handle, "_DCK", &tmp);
+       if (ACPI_FAILURE(status)) {
+               return 0;
+       }
+       return 1;
+}
+
 /* callback routine to check the existence of ejectable slots */
 static acpi_status
 is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int *count = (int *)context;
 
-       if (is_ejectable(handle)) {
+       if (is_ejectable(handle) || (handle == dock_bridge.dock_bridge_handle)) 
{
                (*count)++;
                /* only one ejectable slot is enough */
                return AE_CTRL_TERMINATE;
@@ -120,7 +132,9 @@ is_ejectable_slot(acpi_handle handle, u3
 }
 
 
-static acpi_status handle_dock(struct acpiphp_func *func, int dock)
+
+
+static acpi_status handle_dock(int dock)
 {
        acpi_status status;
        struct acpi_object_list arg_list;
@@ -134,10 +148,13 @@ static acpi_status handle_dock(struct ac
        arg_list.pointer = &arg;
        arg.type = ACPI_TYPE_INTEGER;
        arg.integer.value = dock;
-       status = acpi_evaluate_object(func->handle, "_DCK",
+       status = acpi_evaluate_object(dock_bridge.dck_handle, "_DCK",
                                        &arg_list, &buffer);
        if (ACPI_FAILURE(status))
                err("%s: failed to dock!!\n", MY_NAME);
+       acpi_os_free(buffer.pointer);
+
+       dbg("%s: exit\n", __FUNCTION__);
 
        return status;
 }
@@ -157,6 +174,7 @@ register_slot(acpi_handle handle, u32 lv
        int device, function;
        static int num_slots = 0;       /* XXX if we support I/O node 
hotplug... */
 
+
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
 
        if (ACPI_FAILURE(status))
@@ -164,9 +182,10 @@ register_slot(acpi_handle handle, u32 lv
 
        status = acpi_get_handle(handle, "_EJ0", &tmp);
 
-       if (ACPI_FAILURE(status))
+       if ((handle != dock_bridge.dock_bridge_handle) && ACPI_FAILURE(status))
                return AE_OK;
 
+
        device = (adr >> 16) & 0xffff;
        function = adr & 0xffff;
 
@@ -178,7 +197,8 @@ register_slot(acpi_handle handle, u32 lv
        INIT_LIST_HEAD(&newfunc->sibling);
        newfunc->handle = handle;
        newfunc->function = function;
-       newfunc->flags = FUNC_HAS_EJ0;
+       if (ACPI_SUCCESS(status))
+               newfunc->flags = FUNC_HAS_EJ0;
 
        if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
                newfunc->flags |= FUNC_HAS_STA;
@@ -189,6 +209,9 @@ register_slot(acpi_handle handle, u32 lv
        if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
                newfunc->flags |= FUNC_HAS_PS3;
 
+       if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
+               newfunc->flags |= FUNC_HAS_DCK;
+
        status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
        if (ACPI_FAILURE(status))
                sun = -1;
@@ -236,24 +259,22 @@ register_slot(acpi_handle handle, u32 lv
                slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
        }
 
-       /* install dock notify handler */
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) {
-               newfunc->flags |= FUNC_HAS_DCK;
-               INIT_WORK(&dock_task, dock, slot);
-       }
 
        /* install notify handler */
-       status = acpi_install_notify_handler(handle,
+       if (!(newfunc->flags & FUNC_HAS_DCK)) {
+               status = acpi_install_notify_handler(handle,
                                             ACPI_SYSTEM_NOTIFY,
                                             handle_hotplug_event_func,
                                             newfunc);
-
-       if (ACPI_FAILURE(status)) {
-               err("failed to register interrupt notify handler\n");
-               return status;
+               if (ACPI_FAILURE(status))
+                       err("failed to register interrupt notify handler\n");
+       } else if (handle == dock_bridge.dock_bridge_handle) {
+               dock_bridge.func = newfunc;
+               dock_bridge.slot = slot;
+               status = AE_OK;
        }
 
-       return AE_OK;
+       return status;
 }
 
 
@@ -544,11 +565,13 @@ static void cleanup_bridge(struct acpiph
                list_for_each_safe (list, tmp, &slot->funcs) {
                        struct acpiphp_func *func;
                        func = list_entry(list, struct acpiphp_func, sibling);
-                       status = acpi_remove_notify_handler(func->handle,
+                       if (!(func->flags & FUNC_HAS_DCK)) {
+                               status = 
acpi_remove_notify_handler(func->handle,
                                                ACPI_SYSTEM_NOTIFY,
                                                handle_hotplug_event_func);
-                       if (ACPI_FAILURE(status))
-                               err("failed to remove notify handler\n");
+                               if (ACPI_FAILURE(status))
+                                       err("failed to remove notify 
handler\n");
+                       }
                        pci_dev_put(func->pci_dev);
                        list_del(list);
                        kfree(func);
@@ -713,33 +736,6 @@ static int acpiphp_configure_ioapics(acp
        return 0;
 }
 
-/*
- * the _DCK method can do funny things... and sometimes not
- * hah-hah funny.
- */
-static void post_dock_fixups(struct acpiphp_slot *slot,
-                            struct acpiphp_func *func)
-{
-       struct pci_bus *bus = slot->bridge->pci_bus;
-       u32 buses;
-
-       /* fixup bad _DCK function that rewrites
-        * secondary bridge on slot
-        */
-       pci_read_config_dword(bus->self,
-                               PCI_PRIMARY_BUS,
-                               &buses);
-
-       if (((buses >> 8) & 0xff) != bus->secondary) {
-               buses = (buses & 0xff000000)
-                       | ((unsigned int)(bus->primary)     <<  0)
-                       | ((unsigned int)(bus->secondary)   <<  8)
-                       | ((unsigned int)(bus->subordinate) << 16);
-               pci_write_config_dword(bus->self,
-                                       PCI_PRIMARY_BUS,
-                                       buses);
-       }
-}
 
 
 static int acpiphp_bus_add(struct acpiphp_func *func)
@@ -771,26 +767,32 @@ static int acpiphp_bus_add(struct acpiph
 
 
 
-static void dock(void *data)
+
+/*
+ * the _DCK method can do funny things... and sometimes not
+ * hah-hah funny.
+ */
+static void post_dock_fixups(void)
 {
-       struct list_head *l;
-       struct acpiphp_func *func;
-       struct acpiphp_slot *slot = data;
+       struct pci_bus *bus = dock_bridge.slot->bridge->pci_bus;
+       u32 buses;
 
-       mutex_lock(&slot->crit_sect);
-       list_for_each(l, &slot->funcs) {
-               func = list_entry(l, struct acpiphp_func, sibling);
-               if (func->flags & FUNC_HAS_DCK) {
-                       handle_dock(func, 1);
-                       post_dock_fixups(slot, func);
-                       slot->flags |= SLOT_POWEREDON;
-                       if (get_slot_status(slot) == ACPI_STA_ALL) {
-                               enable_device(slot);
-                       }
-               }
+       /* fixup bad _DCK function that rewrites
+        * secondary bridge on slot
+        */
+       pci_read_config_dword(bus->self,
+                               PCI_PRIMARY_BUS,
+                               &buses);
+
+       if (((buses >> 8) & 0xff) != bus->secondary) {
+               buses = (buses & 0xff000000)
+                       | ((unsigned int)(bus->primary)     <<  0)
+                       | ((unsigned int)(bus->secondary)   <<  8)
+                       | ((unsigned int)(bus->subordinate) << 16);
+               pci_write_config_dword(bus->self,
+                                       PCI_PRIMARY_BUS,
+                                       buses);
        }
-       slot->flags &= (~SLOT_DOCKING);
-       mutex_unlock(&slot->crit_sect);
 }
 
 
@@ -819,19 +821,6 @@ static int power_on_slot(struct acpiphp_
                        } else
                                break;
                }
-
-               if (func->flags & FUNC_HAS_DCK) {
-                       dbg("%s: executing _DCK\n", __FUNCTION__);
-                       slot->flags |= SLOT_DOCKING;
-                       /*
-                        * FIXME - work around for acpi.  Right
-                        * now if we call _DCK from this thread,
-                        * we block forever.
-                        */
-                       schedule_work(&dock_task);
-                       retval = -1;
-                       goto err_exit;
-               }
        }
 
        /* TBD: evaluate _STA to check if the slot is enabled */
@@ -857,11 +846,6 @@ static int power_off_slot(struct acpiphp
 
        list_for_each (l, &slot->funcs) {
                func = list_entry(l, struct acpiphp_func, sibling);
-               if (func->flags & FUNC_HAS_DCK) {
-                       dbg("%s: undock commencing\n", __FUNCTION__);
-                       handle_dock(func, 0);
-                       dbg("%s: undock complete\n", __FUNCTION__);
-               }
                if (func->flags & FUNC_HAS_PS3) {
                        status = acpi_evaluate_object(func->handle, "_PS3", 
NULL, NULL);
                        if (ACPI_FAILURE(status)) {
@@ -871,6 +855,7 @@ static int power_off_slot(struct acpiphp
                        } else
                                break;
                }
+
        }
 
        /* TBD: evaluate _STA to check if the slot is disabled */
@@ -882,6 +867,8 @@ static int power_off_slot(struct acpiphp
 }
 
 
+
+
 /**
  * get_func - given pci_dev & slot, get the matching acpiphp_func
  * @slot: slot to be scanned.
@@ -889,22 +876,27 @@ static int power_off_slot(struct acpiphp
  *
  * This function will check the list of acpiphp functions for
  * this slot and return the one that represents the given
- * pci_dev structure.
+ * pci_dev structure.  This function will incremente the ref
+ * pointer of the pci_dev struct as a side effect, so the caller
+ * must call pci_dev_put when they are done.
  */
 static struct acpiphp_func * get_func(struct acpiphp_slot *slot,
                                        struct pci_dev *dev)
 {
-       struct list_head *l;
-       struct acpiphp_func *func;
+       struct acpiphp_func *func = NULL;
        struct pci_bus *bus = slot->bridge->pci_bus;
+       struct pci_dev *pdev;
 
-       list_for_each (l, &slot->funcs) {
-               func = list_entry(l, struct acpiphp_func, sibling);
-               if (pci_get_slot(bus, PCI_DEVFN(slot->device,
-                                       func->function)) == dev)
-                       return func;
+       list_for_each_entry (func, &slot->funcs, sibling) {
+               pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
+                                       func->function));
+               if (pdev) {
+                       if (pdev == dev)
+                               break;
+                       pci_dev_put(pdev);
+               }
        }
-       return NULL;
+       return func;
 }
 
 
@@ -987,8 +979,11 @@ static int enable_device(struct acpiphp_
                                if (pass && dev->subordinate) {
                                        pci_bus_size_bridges(dev->subordinate);
                                        func = get_func(slot, dev);
-                                       if (func)
+                                       if (func) {
                                                acpiphp_bus_add(func);
+                                               /* side effect of get_func() */
+                                               pci_dev_put(dev);
+                                       }
                                }
                        }
                }
@@ -1306,6 +1301,7 @@ static void handle_bridge_insertion(acpi
  * ACPI event handlers
  */
 
+
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
  *
@@ -1439,6 +1435,47 @@ static void handle_hotplug_event_func(ac
        }
 }
 
+
+
+static void
+handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
+{
+       acpi_handle dock = dock_bridge.dock_bridge_handle;
+
+       switch (type) {
+               case ACPI_NOTIFY_BUS_CHECK:
+                       dbg("%s: Bus check notify\n",
+                               __FUNCTION__);
+                       dock_bridge.flags |= SLOT_DOCKING;
+                       handle_dock(1);
+                       if (dock) {
+                               post_dock_fixups();
+                               handle_hotplug_event_func(dock,
+                                       type, dock_bridge.func);
+                       }
+                       dock_bridge.flags &= ~(SLOT_DOCKING);
+                       dock_bridge.last_dock_time = jiffies;
+                       break;
+               case ACPI_NOTIFY_EJECT_REQUEST:
+                       if (dock_bridge.flags & SLOT_DOCKING ||
+                               dock_bridge.last_dock_time == jiffies) {
+                               dbg("%s: Ignore bogus eject request\n",
+                                       __FUNCTION__);
+                       } else {
+                               dbg("%s: Eject notify\n", __FUNCTION__);
+                               handle_dock(0);
+                               handle_hotplug_event_func(dock,
+                                       type, dock_bridge.func);
+                       }
+                       break;
+               default:
+                       warn("%s: unknown event type 0x%x\n",
+                               __FUNCTION__, type);
+       }
+}
+
+
+
 static int is_root_bridge(acpi_handle handle)
 {
        acpi_status status;
@@ -1468,6 +1505,130 @@ static int is_root_bridge(acpi_handle ha
        return 0;
 }
 
+
+static acpi_status
+find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       acpi_status status;
+       acpi_handle tmp;
+       acpi_handle dck_handle = (acpi_handle) context;
+       char objname[64];
+       char ejd_objname[64];
+       struct acpi_buffer buffer = { .length = sizeof(objname),
+                                     .pointer = objname };
+       struct acpi_buffer ejd_buffer = { .length = sizeof(ejd_objname),
+                                         .pointer = ejd_objname };
+       union acpi_object *ejd_obj;
+       union acpi_object *dck_obj;
+
+       dbg("%s: enter\n", __FUNCTION__);
+
+       status = acpi_get_handle(handle, "_EJD", &tmp);
+       if (ACPI_FAILURE(status)) {
+               dbg("%s: no _EJD methods found\n", __FUNCTION__);
+               return 0;
+       }
+
+       /* make sure we are dependent on the dock device */
+       acpi_get_name(dck_handle, ACPI_FULL_PATHNAME, &buffer);
+       status = acpi_evaluate_object(handle, "_EJD", NULL, &ejd_buffer);
+       if (ACPI_FAILURE(status)) {
+               err("Unable to execute _EJD!\n");
+               return 0;
+       }
+
+       ejd_obj = ejd_buffer.pointer;
+       dck_obj = buffer.pointer;
+       if (!strncmp(ejd_obj->string.pointer, dck_obj->string.pointer,
+               ejd_obj->string.length)) {
+               dbg("%s: found device dependent on dock\n", __FUNCTION__);
+               /* ok, this device is dependent on the dock device,
+                * if it was the actual dock bridge, it would have
+                * a PRT associated with it.
+                */
+               status = acpi_get_handle(handle, "_PRT", &tmp);
+               if (ACPI_FAILURE(status))
+                       return 0;
+
+               /* yippee, we found the dock bridge! */
+               dbg("%s: found dock bridge\n", __FUNCTION__);
+               *(rv) = handle;
+               return AE_CTRL_TERMINATE;
+       }
+       return AE_OK;
+}
+
+
+static acpi_handle
+get_dock_handle(acpi_handle handle)
+{
+       acpi_handle dock_bridge_handle = NULL;
+
+       dbg("%s: enter\n", __FUNCTION__);
+
+       /*
+        * first see if we are the dock bridge.
+        */
+       if (is_ejectable(handle))
+               return handle;
+
+       dbg("%s: not ejectable\n", __FUNCTION__);
+
+       /*
+        * otherwise, we are going to have to find
+        * the dock bridge by checking the _EJD list.
+        */
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+               ACPI_UINT32_MAX, find_dock_ejd, handle, &dock_bridge_handle);
+
+       return dock_bridge_handle;
+}
+
+
+
+static acpi_status
+find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       int *count = (int *)context;
+
+       dbg("%s: enter\n", __FUNCTION__);
+
+       if (is_dock(handle)) {
+               /* found a dock.  Now we have to determine if
+                * the _DCK method is within the scope of the
+                * dock bridge, or outside it (as in the IBM x-series)
+                */
+               dbg("%s: found dock\n", __FUNCTION__);
+               dock_bridge.dock_bridge_handle = get_dock_handle(handle);
+               dock_bridge.dck_handle = handle;
+               acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                       handle_hotplug_event_dock, NULL);
+               (*count)++;
+       }
+
+       return AE_OK;
+}
+
+
+
+
+static int
+find_dock_bridge(void)
+{
+       int num = 0;
+
+       /* start from the root object, because some laptops define
+        * _DCK methods outside the scope of PCI (IBM x-series laptop)
+        */
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                       ACPI_UINT32_MAX, find_dock, &num, NULL);
+
+       return num;
+}
+
+
+
+
 static acpi_status
 find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
@@ -1494,6 +1655,8 @@ int __init acpiphp_glue_init(void)
 {
        int num = 0;
 
+       num = find_dock_bridge();
+
        acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
                        ACPI_UINT32_MAX, find_root_bridges, &num, NULL);
 
@@ -1513,6 +1676,17 @@ int __init acpiphp_glue_init(void)
  */
 void __exit acpiphp_glue_exit(void)
 {
+       acpi_handle handle = dock_bridge.dck_handle;
+
+       /* if we have a dock station handle, we should
+        * remove the notify handler
+        */
+       if (handle) {
+               if (ACPI_FAILURE(acpi_remove_notify_handler(handle,
+                       ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
+                       err("failed to remove dock notify handler\n");
+       }
+
        acpi_pci_unregister_driver(&acpi_pci_hp_driver);
 }
 
@@ -1537,6 +1711,12 @@ int __init acpiphp_get_num_slots(void)
                num_slots += bridge->nr_slots;
        }
 
+       /* it's possible to have a dock station that doesn't actually
+        * use a pci dock bridge.  For now, continue to allow this
+        * to be handled by this driver.
+        */
+       if (dock_bridge.dck_handle && !dock_bridge.dock_bridge_handle)
+               num_slots++;
        dbg("Total %d slots\n", num_slots);
        return num_slots;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to