dock: introduce .uevent for devices in dock, eg libata
Shaohua Li [Thu, 28 Aug 2008 02:06:16 +0000 (10:06 +0800)]
dock's uevent reported itself, not ata. It might be difficult to find an
ata device just according to a dock. This patch introduces docking ops
for each device in a dock. when docking, dock driver can send device
specific uevent. This should help dock station too (not just bay)

Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Acked-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Len Brown <len.brown@intel.com>

drivers/acpi/dock.c
drivers/ata/libata-acpi.c
drivers/pci/hotplug/acpiphp_glue.c
include/acpi/acpi_drivers.h

index f19f643..ac7dfef 100644 (file)
@@ -75,7 +75,7 @@ struct dock_dependent_device {
        struct list_head list;
        struct list_head hotplug_list;
        acpi_handle handle;
-       acpi_notify_handler handler;
+       struct acpi_dock_ops *ops;
        void *context;
 };
 
@@ -385,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
         * First call driver specific hotplug functions
         */
        list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
-               if (dd->handler)
-                       dd->handler(dd->handle, event, dd->context);
+               if (dd->ops && dd->ops->handler)
+                       dd->ops->handler(dd->handle, event, dd->context);
        }
 
        /*
@@ -409,6 +409,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
        struct device *dev = &ds->dock_device->dev;
        char event_string[13];
        char *envp[] = { event_string, NULL };
+       struct dock_dependent_device *dd;
 
        if (num == UNDOCK_EVENT)
                sprintf(event_string, "EVENT=undock");
@@ -419,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
         * Indicate that the status of the dock station has
         * changed.
         */
-       kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+       if (num == DOCK_EVENT)
+               kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
+       list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
+               if (dd->ops && dd->ops->uevent)
+                       dd->ops->uevent(dd->handle, event, dd->context);
+       if (num != DOCK_EVENT)
+               kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 /**
@@ -588,7 +596,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
 /**
  * register_hotplug_dock_device - register a hotplug function
  * @handle: the handle of the device
- * @handler: the acpi_notifier_handler to call after docking
+ * @ops: handlers to call after docking
  * @context: device specific data
  *
  * If a driver would like to perform a hotplug operation after a dock
@@ -596,7 +604,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
  * the dock driver after _DCK is executed.
  */
 int
-register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
+register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
                             void *context)
 {
        struct dock_dependent_device *dd;
@@ -612,7 +620,7 @@ register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
        list_for_each_entry(dock_station, &dock_stations, sibiling) {
                dd = find_dock_dependent_device(dock_station, handle);
                if (dd) {
-                       dd->handler = handler;
+                       dd->ops = ops;
                        dd->context = context;
                        dock_add_hotplug_device(dock_station, dd);
                        return 0;
index 97727be..c012307 100644 (file)
@@ -209,6 +209,46 @@ static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
        ata_acpi_handle_hotplug(ap, NULL, event);
 }
 
+static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
+       u32 event)
+{
+       struct kobject *kobj = NULL;
+       char event_string[20];
+       char *envp[] = { event_string, NULL };
+
+       if (dev) {
+               if (dev->sdev)
+                       kobj = &dev->sdev->sdev_gendev.kobj;
+       } else
+               kobj = &ap->dev->kobj;
+
+       if (kobj) {
+               snprintf(event_string, 20, "BAY_EVENT=%d", event);
+               kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+       }
+}
+
+static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+{
+       ata_acpi_uevent(data, NULL, event);
+}
+
+static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+{
+       struct ata_device *dev = data;
+       ata_acpi_uevent(dev->link->ap, dev, event);
+}
+
+static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
+       .handler = ata_acpi_dev_notify_dock,
+       .uevent = ata_acpi_dev_uevent,
+};
+
+static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
+       .handler = ata_acpi_ap_notify_dock,
+       .uevent = ata_acpi_ap_uevent,
+};
+
 /**
  * ata_acpi_associate - associate ATA host with ACPI objects
  * @host: target ATA host
@@ -244,7 +284,7 @@ void ata_acpi_associate(struct ata_host *host)
                if (ap->acpi_handle) {
                        /* we might be on a docking station */
                        register_hotplug_dock_device(ap->acpi_handle,
-                                            ata_acpi_ap_notify_dock, ap);
+                                            &ata_acpi_ap_dock_ops, ap);
                }
 
                for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
@@ -253,7 +293,7 @@ void ata_acpi_associate(struct ata_host *host)
                        if (dev->acpi_handle) {
                                /* we might be on a docking station */
                                register_hotplug_dock_device(dev->acpi_handle,
-                                            ata_acpi_dev_notify_dock, dev);
+                                            &ata_acpi_dev_dock_ops, dev);
                        }
                }
        }
index a3e4705..db54c5e 100644 (file)
@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
 }
 
 
-
+static struct acpi_dock_ops acpiphp_dock_ops = {
+       .handler = handle_hotplug_event_func,
+};
 
 /* callback routine to register each ACPI PCI slot object */
 static acpi_status
@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                 */
                newfunc->flags &= ~FUNC_HAS_EJ0;
                if (register_hotplug_dock_device(handle,
-                       handle_hotplug_event_func, newfunc))
+                       &acpiphp_dock_ops, newfunc))
                        dbg("failed to register dock device\n");
 
                /* we need to be notified when dock events happen
index e5f38e5..4f5042a 100644 (file)
@@ -115,12 +115,17 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
 /*--------------------------------------------------------------------------
                                   Dock Station
   -------------------------------------------------------------------------- */
+struct acpi_dock_ops {
+       acpi_notify_handler handler;
+       acpi_notify_handler uevent;
+};
+
 #if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
 extern int is_dock_device(acpi_handle handle);
 extern int register_dock_notifier(struct notifier_block *nb);
 extern void unregister_dock_notifier(struct notifier_block *nb);
 extern int register_hotplug_dock_device(acpi_handle handle,
-                                       acpi_notify_handler handler,
+                                       struct acpi_dock_ops *ops,
                                        void *context);
 extern void unregister_hotplug_dock_device(acpi_handle handle);
 #else
@@ -136,7 +141,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
 {
 }
 static inline int register_hotplug_dock_device(acpi_handle handle,
-                                              acpi_notify_handler handler,
+                                              struct acpi_dock_ops *ops,
                                               void *context)
 {
        return -ENODEV;