|
@@ -51,8 +51,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
|
|
|
" the driver to wait for userspace to write the undock sysfs file "
|
|
|
" before undocking");
|
|
|
|
|
|
-static struct atomic_notifier_head dock_notifier_list;
|
|
|
-
|
|
|
static const struct acpi_device_id dock_device_ids[] = {
|
|
|
{"LNXDOCK", 0},
|
|
|
{"", 0},
|
|
@@ -63,8 +61,6 @@ struct dock_station {
|
|
|
acpi_handle handle;
|
|
|
unsigned long last_dock_time;
|
|
|
u32 flags;
|
|
|
- spinlock_t dd_lock;
|
|
|
- struct mutex hp_lock;
|
|
|
struct list_head dependent_devices;
|
|
|
|
|
|
struct list_head sibling;
|
|
@@ -91,6 +87,12 @@ struct dock_dependent_device {
|
|
|
#define DOCK_EVENT 3
|
|
|
#define UNDOCK_EVENT 2
|
|
|
|
|
|
+enum dock_callback_type {
|
|
|
+ DOCK_CALL_HANDLER,
|
|
|
+ DOCK_CALL_FIXUP,
|
|
|
+ DOCK_CALL_UEVENT,
|
|
|
+};
|
|
|
+
|
|
|
/*****************************************************************************
|
|
|
* Dock Dependent device functions *
|
|
|
*****************************************************************************/
|
|
@@ -101,7 +103,7 @@ struct dock_dependent_device {
|
|
|
*
|
|
|
* Add the dependent device to the dock's dependent device list.
|
|
|
*/
|
|
|
-static int
|
|
|
+static int __init
|
|
|
add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
|
|
|
{
|
|
|
struct dock_dependent_device *dd;
|
|
@@ -112,14 +114,21 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
|
|
|
|
|
|
dd->handle = handle;
|
|
|
INIT_LIST_HEAD(&dd->list);
|
|
|
-
|
|
|
- spin_lock(&ds->dd_lock);
|
|
|
list_add_tail(&dd->list, &ds->dependent_devices);
|
|
|
- spin_unlock(&ds->dd_lock);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void remove_dock_dependent_devices(struct dock_station *ds)
|
|
|
+{
|
|
|
+ struct dock_dependent_device *dd, *aux;
|
|
|
+
|
|
|
+ list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
|
|
|
+ list_del(&dd->list);
|
|
|
+ kfree(dd);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* dock_init_hotplug - Initialize a hotplug device on a docking station.
|
|
|
* @dd: Dock-dependent device.
|
|
@@ -135,19 +144,16 @@ static int dock_init_hotplug(struct dock_dependent_device *dd,
|
|
|
int ret = 0;
|
|
|
|
|
|
mutex_lock(&hotplug_lock);
|
|
|
-
|
|
|
- if (dd->hp_context) {
|
|
|
+ if (WARN_ON(dd->hp_context)) {
|
|
|
ret = -EEXIST;
|
|
|
} else {
|
|
|
dd->hp_refcount = 1;
|
|
|
dd->hp_ops = ops;
|
|
|
dd->hp_context = context;
|
|
|
dd->hp_release = release;
|
|
|
+ if (init)
|
|
|
+ init(context);
|
|
|
}
|
|
|
-
|
|
|
- if (!WARN_ON(ret) && init)
|
|
|
- init(context);
|
|
|
-
|
|
|
mutex_unlock(&hotplug_lock);
|
|
|
return ret;
|
|
|
}
|
|
@@ -162,27 +168,22 @@ static int dock_init_hotplug(struct dock_dependent_device *dd,
|
|
|
*/
|
|
|
static void dock_release_hotplug(struct dock_dependent_device *dd)
|
|
|
{
|
|
|
- void (*release)(void *) = NULL;
|
|
|
- void *context = NULL;
|
|
|
-
|
|
|
mutex_lock(&hotplug_lock);
|
|
|
-
|
|
|
if (dd->hp_context && !--dd->hp_refcount) {
|
|
|
+ void (*release)(void *) = dd->hp_release;
|
|
|
+ void *context = dd->hp_context;
|
|
|
+
|
|
|
dd->hp_ops = NULL;
|
|
|
- context = dd->hp_context;
|
|
|
dd->hp_context = NULL;
|
|
|
- release = dd->hp_release;
|
|
|
dd->hp_release = NULL;
|
|
|
+ if (release)
|
|
|
+ release(context);
|
|
|
}
|
|
|
-
|
|
|
- if (release && context)
|
|
|
- release(context);
|
|
|
-
|
|
|
mutex_unlock(&hotplug_lock);
|
|
|
}
|
|
|
|
|
|
static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
|
|
|
- bool uevent)
|
|
|
+ enum dock_callback_type cb_type)
|
|
|
{
|
|
|
acpi_notify_handler cb = NULL;
|
|
|
bool run = false;
|
|
@@ -192,8 +193,18 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
|
|
|
if (dd->hp_context) {
|
|
|
run = true;
|
|
|
dd->hp_refcount++;
|
|
|
- if (dd->hp_ops)
|
|
|
- cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
|
|
|
+ if (dd->hp_ops) {
|
|
|
+ switch (cb_type) {
|
|
|
+ case DOCK_CALL_FIXUP:
|
|
|
+ cb = dd->hp_ops->fixup;
|
|
|
+ break;
|
|
|
+ case DOCK_CALL_UEVENT:
|
|
|
+ cb = dd->hp_ops->uevent;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ cb = dd->hp_ops->handler;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&hotplug_lock);
|
|
@@ -220,63 +231,17 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
|
|
|
{
|
|
|
struct dock_dependent_device *dd;
|
|
|
|
|
|
- spin_lock(&ds->dd_lock);
|
|
|
- list_for_each_entry(dd, &ds->dependent_devices, list) {
|
|
|
- if (handle == dd->handle) {
|
|
|
- spin_unlock(&ds->dd_lock);
|
|
|
+ list_for_each_entry(dd, &ds->dependent_devices, list)
|
|
|
+ if (handle == dd->handle)
|
|
|
return dd;
|
|
|
- }
|
|
|
- }
|
|
|
- spin_unlock(&ds->dd_lock);
|
|
|
+
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
* Dock functions *
|
|
|
*****************************************************************************/
|
|
|
-/**
|
|
|
- * is_dock - see if a device is a dock station
|
|
|
- * @handle: acpi handle of the device
|
|
|
- *
|
|
|
- * If an acpi object has a _DCK method, then it is by definition a dock
|
|
|
- * station, so return true.
|
|
|
- */
|
|
|
-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;
|
|
|
-}
|
|
|
-
|
|
|
-static int is_ejectable(acpi_handle handle)
|
|
|
-{
|
|
|
- acpi_status status;
|
|
|
- acpi_handle tmp;
|
|
|
-
|
|
|
- status = acpi_get_handle(handle, "_EJ0", &tmp);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- return 0;
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int is_ata(acpi_handle handle)
|
|
|
-{
|
|
|
- acpi_handle tmp;
|
|
|
-
|
|
|
- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
|
|
- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
|
|
- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
|
|
- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
|
|
- return 1;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int is_battery(acpi_handle handle)
|
|
|
+static int __init is_battery(acpi_handle handle)
|
|
|
{
|
|
|
struct acpi_device_info *info;
|
|
|
int ret = 1;
|
|
@@ -292,17 +257,13 @@ static int is_battery(acpi_handle handle)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int is_ejectable_bay(acpi_handle handle)
|
|
|
+/* Check whether ACPI object is an ejectable battery or disk bay */
|
|
|
+static bool __init is_ejectable_bay(acpi_handle handle)
|
|
|
{
|
|
|
- acpi_handle phandle;
|
|
|
+ if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
|
|
|
+ return true;
|
|
|
|
|
|
- if (!is_ejectable(handle))
|
|
|
- return 0;
|
|
|
- if (is_battery(handle) || is_ata(handle))
|
|
|
- return 1;
|
|
|
- if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
|
|
|
- return 1;
|
|
|
- return 0;
|
|
|
+ return acpi_bay_match(handle);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -320,7 +281,7 @@ int is_dock_device(acpi_handle handle)
|
|
|
if (!dock_station_count)
|
|
|
return 0;
|
|
|
|
|
|
- if (is_dock(handle))
|
|
|
+ if (acpi_dock_match(handle))
|
|
|
return 1;
|
|
|
|
|
|
list_for_each_entry(dock_station, &dock_stations, sibling)
|
|
@@ -359,10 +320,8 @@ static int dock_present(struct dock_station *ds)
|
|
|
* handle if one does not exist already. This should cause
|
|
|
* acpi to scan for drivers for the given devices, and call
|
|
|
* matching driver's add routine.
|
|
|
- *
|
|
|
- * Returns a pointer to the acpi_device corresponding to the handle.
|
|
|
*/
|
|
|
-static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
|
|
|
+static void dock_create_acpi_device(acpi_handle handle)
|
|
|
{
|
|
|
struct acpi_device *device;
|
|
|
int ret;
|
|
@@ -375,10 +334,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
|
|
|
ret = acpi_bus_scan(handle);
|
|
|
if (ret)
|
|
|
pr_debug("error adding bus, %x\n", -ret);
|
|
|
-
|
|
|
- acpi_bus_get_device(handle, &device);
|
|
|
}
|
|
|
- return device;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -397,9 +353,29 @@ static void dock_remove_acpi_device(acpi_handle handle)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * hotplug_dock_devices - insert or remove devices on the dock station
|
|
|
+ * hot_remove_dock_devices - Remove dock station devices.
|
|
|
+ * @ds: Dock station.
|
|
|
+ */
|
|
|
+static void hot_remove_dock_devices(struct dock_station *ds)
|
|
|
+{
|
|
|
+ struct dock_dependent_device *dd;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Walk the list in reverse order so that devices that have been added
|
|
|
+ * last are removed first (in case there are some indirect dependencies
|
|
|
+ * between them).
|
|
|
+ */
|
|
|
+ list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
|
|
|
+ dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
|
|
|
+
|
|
|
+ list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
|
|
|
+ dock_remove_acpi_device(dd->handle);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hotplug_dock_devices - Insert devices on a dock station.
|
|
|
* @ds: the dock station
|
|
|
- * @event: either bus check or eject request
|
|
|
+ * @event: either bus check or device check request
|
|
|
*
|
|
|
* Some devices on the dock station need to have drivers called
|
|
|
* to perform hotplug operations after a dock event has occurred.
|
|
@@ -410,27 +386,21 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
|
|
{
|
|
|
struct dock_dependent_device *dd;
|
|
|
|
|
|
- mutex_lock(&ds->hp_lock);
|
|
|
+ /* Call driver specific post-dock fixups. */
|
|
|
+ list_for_each_entry(dd, &ds->dependent_devices, list)
|
|
|
+ dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
|
|
|
|
|
|
- /*
|
|
|
- * First call driver specific hotplug functions
|
|
|
- */
|
|
|
+ /* Call driver specific hotplug functions. */
|
|
|
list_for_each_entry(dd, &ds->dependent_devices, list)
|
|
|
- dock_hotplug_event(dd, event, false);
|
|
|
+ dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
|
|
|
|
|
|
/*
|
|
|
- * Now make sure that an acpi_device is created for each
|
|
|
- * dependent device, or removed if this is an eject request.
|
|
|
- * This will cause acpi_drivers to be stopped/started if they
|
|
|
- * exist
|
|
|
+ * Now make sure that an acpi_device is created for each dependent
|
|
|
+ * device. That will cause scan handlers to be attached to device
|
|
|
+ * objects or acpi_drivers to be stopped/started if they are present.
|
|
|
*/
|
|
|
- list_for_each_entry(dd, &ds->dependent_devices, list) {
|
|
|
- if (event == ACPI_NOTIFY_EJECT_REQUEST)
|
|
|
- dock_remove_acpi_device(dd->handle);
|
|
|
- else
|
|
|
- dock_create_acpi_device(dd->handle);
|
|
|
- }
|
|
|
- mutex_unlock(&ds->hp_lock);
|
|
|
+ list_for_each_entry(dd, &ds->dependent_devices, list)
|
|
|
+ dock_create_acpi_device(dd->handle);
|
|
|
}
|
|
|
|
|
|
static void dock_event(struct dock_station *ds, u32 event, int num)
|
|
@@ -453,43 +423,12 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
|
|
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
|
|
|
|
|
list_for_each_entry(dd, &ds->dependent_devices, list)
|
|
|
- dock_hotplug_event(dd, event, true);
|
|
|
+ dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
|
|
|
|
|
|
if (num != DOCK_EVENT)
|
|
|
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * eject_dock - respond to a dock eject request
|
|
|
- * @ds: the dock station
|
|
|
- *
|
|
|
- * This is called after _DCK is called, to execute the dock station's
|
|
|
- * _EJ0 method.
|
|
|
- */
|
|
|
-static void eject_dock(struct dock_station *ds)
|
|
|
-{
|
|
|
- struct acpi_object_list arg_list;
|
|
|
- union acpi_object arg;
|
|
|
- acpi_status status;
|
|
|
- acpi_handle tmp;
|
|
|
-
|
|
|
- /* all dock devices should have _EJ0, but check anyway */
|
|
|
- status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- pr_debug("No _EJ0 support for dock device\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- arg_list.count = 1;
|
|
|
- arg_list.pointer = &arg;
|
|
|
- arg.type = ACPI_TYPE_INTEGER;
|
|
|
- arg.integer.value = 1;
|
|
|
-
|
|
|
- status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- pr_debug("Failed to evaluate _EJ0!\n");
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* handle_dock - handle a dock event
|
|
|
* @ds: the dock station
|
|
@@ -550,27 +489,6 @@ static inline void complete_undock(struct dock_station *ds)
|
|
|
ds->flags &= ~(DOCK_UNDOCKING);
|
|
|
}
|
|
|
|
|
|
-static void dock_lock(struct dock_station *ds, int lock)
|
|
|
-{
|
|
|
- struct acpi_object_list arg_list;
|
|
|
- union acpi_object arg;
|
|
|
- acpi_status status;
|
|
|
-
|
|
|
- arg_list.count = 1;
|
|
|
- arg_list.pointer = &arg;
|
|
|
- arg.type = ACPI_TYPE_INTEGER;
|
|
|
- arg.integer.value = !!lock;
|
|
|
- status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
|
|
|
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
|
|
- if (lock)
|
|
|
- acpi_handle_warn(ds->handle,
|
|
|
- "Locking device failed (0x%x)\n", status);
|
|
|
- else
|
|
|
- acpi_handle_warn(ds->handle,
|
|
|
- "Unlocking device failed (0x%x)\n", status);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* dock_in_progress - see if we are in the middle of handling a dock event
|
|
|
* @ds: the dock station
|
|
@@ -587,37 +505,6 @@ static int dock_in_progress(struct dock_station *ds)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * register_dock_notifier - add yourself to the dock notifier list
|
|
|
- * @nb: the callers notifier block
|
|
|
- *
|
|
|
- * If a driver wishes to be notified about dock events, they can
|
|
|
- * use this function to put a notifier block on the dock notifier list.
|
|
|
- * this notifier call chain will be called after a dock event, but
|
|
|
- * before hotplugging any new devices.
|
|
|
- */
|
|
|
-int register_dock_notifier(struct notifier_block *nb)
|
|
|
-{
|
|
|
- if (!dock_station_count)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- return atomic_notifier_chain_register(&dock_notifier_list, nb);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(register_dock_notifier);
|
|
|
-
|
|
|
-/**
|
|
|
- * unregister_dock_notifier - remove yourself from the dock notifier list
|
|
|
- * @nb: the callers notifier block
|
|
|
- */
|
|
|
-void unregister_dock_notifier(struct notifier_block *nb)
|
|
|
-{
|
|
|
- if (!dock_station_count)
|
|
|
- return;
|
|
|
-
|
|
|
- atomic_notifier_chain_unregister(&dock_notifier_list, nb);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
|
|
-
|
|
|
/**
|
|
|
* register_hotplug_dock_device - register a hotplug function
|
|
|
* @handle: the handle of the device
|
|
@@ -703,10 +590,10 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
|
|
*/
|
|
|
dock_event(ds, event, UNDOCK_EVENT);
|
|
|
|
|
|
- hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
|
|
+ hot_remove_dock_devices(ds);
|
|
|
undock(ds);
|
|
|
- dock_lock(ds, 0);
|
|
|
- eject_dock(ds);
|
|
|
+ acpi_evaluate_lck(ds->handle, 0);
|
|
|
+ acpi_evaluate_ej0(ds->handle);
|
|
|
if (dock_present(ds)) {
|
|
|
acpi_handle_err(ds->handle, "Unable to undock!\n");
|
|
|
return -EBUSY;
|
|
@@ -717,18 +604,17 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
|
|
|
|
|
/**
|
|
|
* dock_notify - act upon an acpi dock notification
|
|
|
- * @handle: the dock station handle
|
|
|
+ * @ds: dock station
|
|
|
* @event: the acpi event
|
|
|
- * @data: our driver data struct
|
|
|
*
|
|
|
* If we are notified to dock, then check to see if the dock is
|
|
|
* present and then dock. Notify all drivers of the dock event,
|
|
|
* and then hotplug and devices that may need hotplugging.
|
|
|
*/
|
|
|
-static void dock_notify(acpi_handle handle, u32 event, void *data)
|
|
|
+static void dock_notify(struct dock_station *ds, u32 event)
|
|
|
{
|
|
|
- struct dock_station *ds = data;
|
|
|
- struct acpi_device *tmp;
|
|
|
+ acpi_handle handle = ds->handle;
|
|
|
+ struct acpi_device *ad;
|
|
|
int surprise_removal = 0;
|
|
|
|
|
|
/*
|
|
@@ -751,8 +637,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
|
|
switch (event) {
|
|
|
case ACPI_NOTIFY_BUS_CHECK:
|
|
|
case ACPI_NOTIFY_DEVICE_CHECK:
|
|
|
- if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
|
|
|
- &tmp)) {
|
|
|
+ if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
|
|
|
begin_dock(ds);
|
|
|
dock(ds);
|
|
|
if (!dock_present(ds)) {
|
|
@@ -760,12 +645,10 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
|
|
complete_dock(ds);
|
|
|
break;
|
|
|
}
|
|
|
- atomic_notifier_call_chain(&dock_notifier_list,
|
|
|
- event, NULL);
|
|
|
hotplug_dock_devices(ds, event);
|
|
|
complete_dock(ds);
|
|
|
dock_event(ds, event, DOCK_EVENT);
|
|
|
- dock_lock(ds, 1);
|
|
|
+ acpi_evaluate_lck(ds->handle, 1);
|
|
|
acpi_update_all_gpes();
|
|
|
break;
|
|
|
}
|
|
@@ -789,9 +672,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
|
|
}
|
|
|
|
|
|
struct dock_data {
|
|
|
- acpi_handle handle;
|
|
|
- unsigned long event;
|
|
|
struct dock_station *ds;
|
|
|
+ u32 event;
|
|
|
};
|
|
|
|
|
|
static void acpi_dock_deferred_cb(void *context)
|
|
@@ -799,52 +681,31 @@ static void acpi_dock_deferred_cb(void *context)
|
|
|
struct dock_data *data = context;
|
|
|
|
|
|
acpi_scan_lock_acquire();
|
|
|
- dock_notify(data->handle, data->event, data->ds);
|
|
|
+ dock_notify(data->ds, data->event);
|
|
|
acpi_scan_lock_release();
|
|
|
kfree(data);
|
|
|
}
|
|
|
|
|
|
-static int acpi_dock_notifier_call(struct notifier_block *this,
|
|
|
- unsigned long event, void *data)
|
|
|
+static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
|
|
|
{
|
|
|
- struct dock_station *dock_station;
|
|
|
- acpi_handle handle = data;
|
|
|
+ struct dock_data *dd;
|
|
|
|
|
|
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
|
|
|
&& event != ACPI_NOTIFY_EJECT_REQUEST)
|
|
|
- return 0;
|
|
|
-
|
|
|
- acpi_scan_lock_acquire();
|
|
|
-
|
|
|
- list_for_each_entry(dock_station, &dock_stations, sibling) {
|
|
|
- if (dock_station->handle == handle) {
|
|
|
- struct dock_data *dd;
|
|
|
- acpi_status status;
|
|
|
-
|
|
|
- dd = kmalloc(sizeof(*dd), GFP_KERNEL);
|
|
|
- if (!dd)
|
|
|
- break;
|
|
|
+ return;
|
|
|
|
|
|
- dd->handle = handle;
|
|
|
- dd->event = event;
|
|
|
- dd->ds = dock_station;
|
|
|
- status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
|
|
|
- dd);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- kfree(dd);
|
|
|
+ dd = kmalloc(sizeof(*dd), GFP_KERNEL);
|
|
|
+ if (dd) {
|
|
|
+ acpi_status status;
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+ dd->ds = data;
|
|
|
+ dd->event = event;
|
|
|
+ status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ kfree(dd);
|
|
|
}
|
|
|
-
|
|
|
- acpi_scan_lock_release();
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
-static struct notifier_block dock_acpi_notifier = {
|
|
|
- .notifier_call = acpi_dock_notifier_call,
|
|
|
-};
|
|
|
-
|
|
|
/**
|
|
|
* find_dock_devices - find devices on the dock station
|
|
|
* @handle: the handle of the device we are examining
|
|
@@ -856,29 +717,16 @@ static struct notifier_block dock_acpi_notifier = {
|
|
|
* check to see if an object has an _EJD method. If it does, then it
|
|
|
* will see if it is dependent on the dock station.
|
|
|
*/
|
|
|
-static acpi_status
|
|
|
-find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|
|
+static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
|
|
|
+ void *context, void **rv)
|
|
|
{
|
|
|
- acpi_status status;
|
|
|
- acpi_handle tmp, parent;
|
|
|
struct dock_station *ds = context;
|
|
|
+ acpi_handle ejd = NULL;
|
|
|
|
|
|
- status = acpi_bus_get_ejd(handle, &tmp);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- /* try the parent device as well */
|
|
|
- status = acpi_get_parent(handle, &parent);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- goto fdd_out;
|
|
|
- /* see if parent is dependent on dock */
|
|
|
- status = acpi_bus_get_ejd(parent, &tmp);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- goto fdd_out;
|
|
|
- }
|
|
|
-
|
|
|
- if (tmp == ds->handle)
|
|
|
+ acpi_bus_get_ejd(handle, &ejd);
|
|
|
+ if (ejd == ds->handle)
|
|
|
add_dock_dependent_device(ds, handle);
|
|
|
|
|
|
-fdd_out:
|
|
|
return AE_OK;
|
|
|
}
|
|
|
|
|
@@ -988,13 +836,13 @@ static struct attribute_group dock_attribute_group = {
|
|
|
*/
|
|
|
static int __init dock_add(acpi_handle handle)
|
|
|
{
|
|
|
- int ret, id;
|
|
|
- struct dock_station ds, *dock_station;
|
|
|
+ struct dock_station *dock_station, ds = { NULL, };
|
|
|
struct platform_device *dd;
|
|
|
+ acpi_status status;
|
|
|
+ int ret;
|
|
|
|
|
|
- id = dock_station_count;
|
|
|
- memset(&ds, 0, sizeof(ds));
|
|
|
- dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
|
|
|
+ dd = platform_device_register_data(NULL, "dock", dock_station_count,
|
|
|
+ &ds, sizeof(ds));
|
|
|
if (IS_ERR(dd))
|
|
|
return PTR_ERR(dd);
|
|
|
|
|
@@ -1004,18 +852,15 @@ static int __init dock_add(acpi_handle handle)
|
|
|
dock_station->dock_device = dd;
|
|
|
dock_station->last_dock_time = jiffies - HZ;
|
|
|
|
|
|
- mutex_init(&dock_station->hp_lock);
|
|
|
- spin_lock_init(&dock_station->dd_lock);
|
|
|
INIT_LIST_HEAD(&dock_station->sibling);
|
|
|
- ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
|
|
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
|
|
|
|
|
/* we want the dock device to send uevents */
|
|
|
dev_set_uevent_suppress(&dd->dev, 0);
|
|
|
|
|
|
- if (is_dock(handle))
|
|
|
+ if (acpi_dock_match(handle))
|
|
|
dock_station->flags |= DOCK_IS_DOCK;
|
|
|
- if (is_ata(handle))
|
|
|
+ if (acpi_ata_match(handle))
|
|
|
dock_station->flags |= DOCK_IS_ATA;
|
|
|
if (is_battery(handle))
|
|
|
dock_station->flags |= DOCK_IS_BAT;
|
|
@@ -1034,11 +879,19 @@ static int __init dock_add(acpi_handle handle)
|
|
|
if (ret)
|
|
|
goto err_rmgroup;
|
|
|
|
|
|
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
|
|
+ dock_notify_handler, dock_station);
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ ret = -ENODEV;
|
|
|
+ goto err_rmgroup;
|
|
|
+ }
|
|
|
+
|
|
|
dock_station_count++;
|
|
|
list_add(&dock_station->sibling, &dock_stations);
|
|
|
return 0;
|
|
|
|
|
|
err_rmgroup:
|
|
|
+ remove_dock_dependent_devices(dock_station);
|
|
|
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
|
|
|
err_unregister:
|
|
|
platform_device_unregister(dd);
|
|
@@ -1058,7 +911,7 @@ err_unregister:
|
|
|
static __init acpi_status
|
|
|
find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|
|
{
|
|
|
- if (is_dock(handle) || is_ejectable_bay(handle))
|
|
|
+ if (acpi_dock_match(handle) || is_ejectable_bay(handle))
|
|
|
dock_add(handle);
|
|
|
|
|
|
return AE_OK;
|
|
@@ -1078,7 +931,6 @@ void __init acpi_dock_init(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- register_acpi_bus_notifier(&dock_acpi_notifier);
|
|
|
pr_info(PREFIX "%s: %d docks/bays found\n",
|
|
|
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
|
|
}
|