diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/container.c | 3 | ||||
-rw-r--r-- | drivers/acpi/dock.c | 171 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 11 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 36 |
4 files changed, 88 insertions, 133 deletions
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 0b6ae6eb5c4a..9c35765ac5e9 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -68,6 +68,9 @@ static int container_device_attach(struct acpi_device *adev, struct device *dev; int ret; + if (adev->flags.is_dock_station) + return 0; + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); if (!cdev) return -ENOMEM; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 5bfd769fc91f..44c6e6c0d545 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -103,8 +103,7 @@ enum dock_callback_type { * * Add the dependent device to the dock's dependent device list. */ -static int __init -add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) +static int add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) { struct dock_dependent_device *dd; @@ -218,6 +217,17 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, dock_release_hotplug(dd); } +static struct dock_station *find_dock_station(acpi_handle handle) +{ + struct dock_station *ds; + + list_for_each_entry(ds, &dock_stations, sibling) + if (ds->handle == handle) + return ds; + + return NULL; +} + /** * find_dock_dependent_device - get a device dependent on this dock * @ds: the dock station @@ -238,33 +248,19 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) return NULL; } -/***************************************************************************** - * Dock functions * - *****************************************************************************/ -static int __init is_battery(acpi_handle handle) +void register_dock_dependent_device(struct acpi_device *adev, + acpi_handle dshandle) { - struct acpi_device_info *info; - int ret = 1; + struct dock_station *ds = find_dock_station(dshandle); + acpi_handle handle = adev->handle; - if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) - return 0; - if (!(info->valid & ACPI_VALID_HID)) - ret = 0; - else - ret = !strcmp("PNP0C0A", info->hardware_id.string); - - kfree(info); - return ret; + if (ds && !find_dock_dependent_device(ds, handle)) + add_dock_dependent_device(ds, handle); } -/* Check whether ACPI object is an ejectable battery or disk bay */ -static bool __init is_ejectable_bay(acpi_handle handle) -{ - if (acpi_has_method(handle, "_EJ0") && is_battery(handle)) - return true; - - return acpi_bay_match(handle); -} +/***************************************************************************** + * Dock functions * + *****************************************************************************/ /** * is_dock_device - see if a device is on a dock station @@ -598,20 +594,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event) } /** - * dock_notify - act upon an acpi dock notification - * @ds: dock station - * @event: the acpi event + * dock_notify - Handle ACPI dock notification. + * @adev: Dock station's ACPI device object. + * @event: Event code. * * 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(struct dock_station *ds, u32 event) +int dock_notify(struct acpi_device *adev, u32 event) { - acpi_handle handle = ds->handle; - struct acpi_device *adev = NULL; + acpi_handle handle = adev->handle; + struct dock_station *ds = find_dock_station(handle); int surprise_removal = 0; + if (!ds) + return -ENODEV; + /* * According to acpi spec 3.0a, if a DEVICE_CHECK notification * is sent and _DCK is present, it is assumed to mean an undock @@ -632,7 +631,6 @@ static void dock_notify(struct dock_station *ds, u32 event) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - acpi_bus_get_device(handle, &adev); if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { begin_dock(ds); dock(ds); @@ -662,49 +660,8 @@ static void dock_notify(struct dock_station *ds, u32 event) else dock_event(ds, event, UNDOCK_EVENT); break; - default: - acpi_handle_err(handle, "Unknown dock event %d\n", event); } -} - -static void acpi_dock_deferred_cb(void *data, u32 event) -{ - acpi_scan_lock_acquire(); - dock_notify(data, event); - acpi_scan_lock_release(); -} - -static void dock_notify_handler(acpi_handle handle, u32 event, void *data) -{ - if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK - && event != ACPI_NOTIFY_EJECT_REQUEST) - return; - - acpi_hotplug_execute(acpi_dock_deferred_cb, data, event); -} - -/** - * find_dock_devices - find devices on the dock station - * @handle: the handle of the device we are examining - * @lvl: unused - * @context: the dock station private data - * @rv: unused - * - * This function is called by acpi_walk_namespace. It will - * 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 __init find_dock_devices(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - struct dock_station *ds = context; - acpi_handle ejd = NULL; - - acpi_bus_get_ejd(handle, &ejd); - if (ejd == ds->handle) - add_dock_dependent_device(ds, handle); - - return AE_OK; + return 0; } /* @@ -803,23 +760,22 @@ static struct attribute_group dock_attribute_group = { }; /** - * dock_add - add a new dock station - * @handle: the dock station handle + * acpi_dock_add - Add a new dock station + * @adev: Dock station ACPI device object. * - * allocated and initialize a new dock station device. Find all devices - * that are on the dock station, and register for dock event notifications. + * allocated and initialize a new dock station device. */ -static int __init dock_add(acpi_handle handle) +void acpi_dock_add(struct acpi_device *adev) { struct dock_station *dock_station, ds = { NULL, }; + acpi_handle handle = adev->handle; struct platform_device *dd; - acpi_status status; int ret; dd = platform_device_register_data(NULL, "dock", dock_station_count, &ds, sizeof(ds)); if (IS_ERR(dd)) - return PTR_ERR(dd); + return; dock_station = dd->dev.platform_data; @@ -837,33 +793,24 @@ static int __init dock_add(acpi_handle handle) dock_station->flags |= DOCK_IS_DOCK; if (acpi_ata_match(handle)) dock_station->flags |= DOCK_IS_ATA; - if (is_battery(handle)) + if (acpi_device_is_battery(handle)) dock_station->flags |= DOCK_IS_BAT; ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); if (ret) goto err_unregister; - /* Find dependent devices */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock_devices, NULL, - dock_station, NULL); - /* add the dock station as a device dependent on itself */ ret = add_dock_dependent_device(dock_station, 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; + adev->flags.is_dock_station = true; + dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n", + dock_station_count); + return; err_rmgroup: remove_dock_dependent_devices(dock_station); @@ -871,38 +818,4 @@ err_rmgroup: err_unregister: platform_device_unregister(dd); acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); - return ret; -} - -/** - * find_dock_and_bay - look for dock stations and bays - * @handle: acpi handle of a device - * @lvl: unused - * @context: unused - * @rv: unused - * - * This is called by acpi_walk_namespace to look for dock stations and bays. - */ -static acpi_status __init -find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - if (acpi_dock_match(handle) || is_ejectable_bay(handle)) - dock_add(handle); - - return AE_OK; -} - -void __init acpi_dock_init(void) -{ - /* look for dock stations and bays */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); - - if (!dock_station_count) { - pr_info(PREFIX "No dock devices found.\n"); - return; - } - - pr_info(PREFIX "%s: %d docks/bays found\n", - ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 143d5df5ec32..00e3220febda 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -37,9 +37,15 @@ void acpi_container_init(void); static inline void acpi_container_init(void) {} #endif #ifdef CONFIG_ACPI_DOCK -void acpi_dock_init(void); +void register_dock_dependent_device(struct acpi_device *adev, + acpi_handle dshandle); +int dock_notify(struct acpi_device *adev, u32 event); +void acpi_dock_add(struct acpi_device *adev); #else -static inline void acpi_dock_init(void) {} +static inline void register_dock_dependent_device(struct acpi_device *adev, + acpi_handle dshandle) {} +static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; } +static inline void acpi_dock_add(struct acpi_device *adev) {} #endif #ifdef CONFIG_ACPI_HOTPLUG_MEMORY void acpi_memory_hotplug_init(void); @@ -91,6 +97,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, struct acpi_device *adev); int acpi_unbind_one(struct device *dev); bool acpi_device_is_present(struct acpi_device *adev); +bool acpi_device_is_battery(acpi_handle handle); /* -------------------------------------------------------------------------- Power Resource diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8bb48bfab1df..ec12d970d78d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -487,7 +487,9 @@ void acpi_device_hotplug(void *data, u32 src) if (adev->handle == INVALID_ACPI_HANDLE) goto err_out; - if (adev->flags.hotplug_notify) { + if (adev->flags.is_dock_station) { + error = dock_notify(adev, src); + } else if (adev->flags.hotplug_notify) { error = acpi_generic_hotplug_event(adev, src); if (error == -EPERM) { ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; @@ -1660,6 +1662,29 @@ bool acpi_bay_match(acpi_handle handle) return acpi_ata_match(phandle); } +bool acpi_device_is_battery(acpi_handle handle) +{ + struct acpi_device_info *info; + bool ret = false; + + if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) + return false; + + if (info->valid & ACPI_VALID_HID) + ret = !strcmp("PNP0C0A", info->hardware_id.string); + + kfree(info); + return ret; +} + +static bool is_ejectable_bay(acpi_handle handle) +{ + if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(handle)) + return true; + + return acpi_bay_match(handle); +} + /* * acpi_dock_match - see if an acpi object has a _DCK method */ @@ -1964,6 +1989,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) { struct acpi_hardware_id *hwid; + if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev->handle)) { + acpi_dock_add(adev); + return; + } list_for_each_entry(hwid, &adev->pnp.ids, list) { struct acpi_scan_handler *handler; @@ -2035,8 +2064,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device) static void acpi_bus_attach(struct acpi_device *device) { struct acpi_device *child; + acpi_handle ejd; int ret; + if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd))) + register_dock_dependent_device(device, ejd); + acpi_bus_get_status(device); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) { @@ -2189,7 +2222,6 @@ int __init acpi_scan_init(void) acpi_cmos_rtc_init(); acpi_container_init(); acpi_memory_hotplug_init(); - acpi_dock_init(); mutex_lock(&acpi_scan_lock); /* |