Commit 47bf31ad authored by Len Brown's avatar Len Brown

Merge branch 'dock' into test

Conflicts:
	drivers/acpi/osl.c
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parents 4538fad5 0a918a94
...@@ -1415,8 +1415,8 @@ M: rdunlap@xenotime.net ...@@ -1415,8 +1415,8 @@ M: rdunlap@xenotime.net
S: Maintained S: Maintained
DOCKING STATION DRIVER DOCKING STATION DRIVER
P: Kristen Carlson Accardi P: Shaohua Li
M: kristen.c.accardi@intel.com M: shaohua.li@intel.com
L: linux-acpi@vger.kernel.org L: linux-acpi@vger.kernel.org
S: Supported S: Supported
......
...@@ -160,15 +160,8 @@ config ACPI_DOCK ...@@ -160,15 +160,8 @@ config ACPI_DOCK
tristate "Dock" tristate "Dock"
depends on EXPERIMENTAL depends on EXPERIMENTAL
help help
This driver adds support for ACPI controlled docking stations This driver adds support for ACPI controlled docking stations and removable
drive bays such as the IBM ultrabay or the Dell Module Bay.
config ACPI_BAY
tristate "Removable Drive Bay (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on ACPI_DOCK
help
This driver adds support for ACPI controlled removable drive
bays such as the IBM ultrabay or the Dell Module Bay.
config ACPI_PROCESSOR config ACPI_PROCESSOR
tristate "Processor" tristate "Processor"
......
...@@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o ...@@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o
obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
......
This diff is collapsed.
...@@ -525,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device) ...@@ -525,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device)
return 0; return 0;
} }
static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
int register_acpi_bus_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
}
EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
void unregister_acpi_bus_notifier(struct notifier_block *nb)
{
blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
/** /**
* acpi_bus_notify * acpi_bus_notify
* --------------- * ---------------
...@@ -535,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ...@@ -535,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
int result = 0; int result = 0;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
blocking_notifier_call_chain(&acpi_bus_notify_list,
type, (void *)handle);
if (acpi_bus_get_device(handle, &device)) if (acpi_bus_get_device(handle, &device))
return; return;
......
This diff is collapsed.
...@@ -682,6 +682,22 @@ static void acpi_os_execute_deferred(struct work_struct *work) ...@@ -682,6 +682,22 @@ static void acpi_os_execute_deferred(struct work_struct *work)
return; return;
} }
static void acpi_os_execute_hp_deferred(struct work_struct *work)
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
if (!dpc) {
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
return;
}
acpi_os_wait_events_complete(NULL);
dpc->function(dpc->context);
kfree(dpc);
return;
}
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_os_execute * FUNCTION: acpi_os_execute
...@@ -697,12 +713,13 @@ static void acpi_os_execute_deferred(struct work_struct *work) ...@@ -697,12 +713,13 @@ static void acpi_os_execute_deferred(struct work_struct *work)
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_os_execute(acpi_execute_type type, static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context) acpi_osd_exec_callback function, void *context, int hp)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_os_dpc *dpc; struct acpi_os_dpc *dpc;
struct workqueue_struct *queue; struct workqueue_struct *queue;
int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n", "Scheduling function [%p(%p)] for deferred execution.\n",
function, context)); function, context));
...@@ -726,9 +743,17 @@ acpi_status acpi_os_execute(acpi_execute_type type, ...@@ -726,9 +743,17 @@ acpi_status acpi_os_execute(acpi_execute_type type,
dpc->function = function; dpc->function = function;
dpc->context = context; dpc->context = context;
if (!hp) {
INIT_WORK(&dpc->work, acpi_os_execute_deferred); INIT_WORK(&dpc->work, acpi_os_execute_deferred);
queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq; queue = (type == OSL_NOTIFY_HANDLER) ?
if (!queue_work(queue, &dpc->work)) { kacpi_notify_wq : kacpid_wq;
ret = queue_work(queue, &dpc->work);
} else {
INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
ret = schedule_work(&dpc->work);
}
if (!ret) {
printk(KERN_ERR PREFIX printk(KERN_ERR PREFIX
"Call to queue_work() failed.\n"); "Call to queue_work() failed.\n");
status = AE_ERROR; status = AE_ERROR;
...@@ -737,8 +762,19 @@ acpi_status acpi_os_execute(acpi_execute_type type, ...@@ -737,8 +762,19 @@ acpi_status acpi_os_execute(acpi_execute_type type,
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
acpi_status acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context)
{
return __acpi_os_execute(type, function, context, 0);
}
EXPORT_SYMBOL(acpi_os_execute); EXPORT_SYMBOL(acpi_os_execute);
acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
void *context)
{
return __acpi_os_execute(0, function, context, 1);
}
void acpi_os_wait_events_complete(void *context) void acpi_os_wait_events_complete(void *context)
{ {
flush_workqueue(kacpid_wq); flush_workqueue(kacpid_wq);
......
...@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) ...@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
} }
static void ata_acpi_eject_device(acpi_handle handle)
{
struct acpi_object_list arg_list;
union acpi_object arg;
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = 1;
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
&arg_list, NULL)))
printk(KERN_ERR "Failed to evaluate _EJ0!\n");
}
/* @ap and @dev are the same as ata_acpi_handle_hotplug() */ /* @ap and @dev are the same as ata_acpi_handle_hotplug() */
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
{ {
...@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) ...@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
* @ap: ATA port ACPI event occurred * @ap: ATA port ACPI event occurred
* @dev: ATA device ACPI event occurred (can be NULL) * @dev: ATA device ACPI event occurred (can be NULL)
* @event: ACPI event which occurred * @event: ACPI event which occurred
* @is_dock_event: boolean indicating whether the event was a dock one
* *
* All ACPI bay / device realted events end up in this function. If * All ACPI bay / device realted events end up in this function. If
* the event is port-wide @dev is NULL. If the event is specific to a * the event is port-wide @dev is NULL. If the event is specific to a
...@@ -171,117 +155,100 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) ...@@ -171,117 +155,100 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
* ACPI notify handler context. May sleep. * ACPI notify handler context. May sleep.
*/ */
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
u32 event, int is_dock_event) u32 event)
{ {
char event_string[12];
char *envp[] = { event_string, NULL };
struct ata_eh_info *ehi = &ap->link.eh_info; struct ata_eh_info *ehi = &ap->link.eh_info;
struct kobject *kobj = NULL;
int wait = 0; int wait = 0;
unsigned long flags; unsigned long flags;
acpi_handle handle, tmphandle; acpi_handle handle;
unsigned long sta;
acpi_status status;
if (dev) { if (dev)
if (dev->sdev)
kobj = &dev->sdev->sdev_gendev.kobj;
handle = dev->acpi_handle; handle = dev->acpi_handle;
} else { else
kobj = &ap->dev->kobj;
handle = ap->acpi_handle; handle = ap->acpi_handle;
}
status = acpi_get_handle(handle, "_EJ0", &tmphandle);
if (ACPI_FAILURE(status))
/* This device does not support hotplug */
return;
if (event == ACPI_NOTIFY_BUS_CHECK ||
event == ACPI_NOTIFY_DEVICE_CHECK)
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
/*
* When dock driver calls into the routine, it will always use
* ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
* ACPI_NOTIFY_EJECT_REQUEST for remove
*/
switch (event) { switch (event) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event"); ata_ehi_push_desc(ehi, "ACPI event");
if (ACPI_FAILURE(status)) {
ata_port_printk(ap, KERN_ERR,
"acpi: failed to determine bay status (0x%x)\n",
status);
break;
}
if (sta) {
ata_ehi_hotplugged(ehi); ata_ehi_hotplugged(ehi);
ata_port_freeze(ap); ata_port_freeze(ap);
} else {
/* The device has gone - unplug it */
ata_acpi_detach_device(ap, dev);
wait = 1;
}
break; break;
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
ata_ehi_push_desc(ehi, "ACPI event"); ata_ehi_push_desc(ehi, "ACPI event");
if (!is_dock_event)
break;
/* undock event - immediate unplug */
ata_acpi_detach_device(ap, dev); ata_acpi_detach_device(ap, dev);
wait = 1; wait = 1;
break; break;
} }
/* make sure kobj doesn't go away while ap->lock is released */
kobject_get(kobj);
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
if (wait) { if (wait)
ata_port_wait_eh(ap); ata_port_wait_eh(ap);
ata_acpi_eject_device(handle);
}
if (kobj && !is_dock_event) {
sprintf(event_string, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
kobject_put(kobj);
} }
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
{ {
struct ata_device *dev = data; struct ata_device *dev = data;
ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1); ata_acpi_handle_hotplug(dev->link->ap, dev, event);
} }
static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
{ {
struct ata_port *ap = data; struct ata_port *ap = data;
ata_acpi_handle_hotplug(ap, NULL, event, 1); ata_acpi_handle_hotplug(ap, NULL, event);
} }
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
u32 event)
{ {
struct ata_device *dev = data; 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;
ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0); if (kobj) {
snprintf(event_string, 20, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
} }
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
{ {
struct ata_port *ap = data; ata_acpi_uevent(data, NULL, event);
}
ata_acpi_handle_hotplug(ap, NULL, event, 0); 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 * ata_acpi_associate - associate ATA host with ACPI objects
* @host: target ATA host * @host: target ATA host
...@@ -315,24 +282,18 @@ void ata_acpi_associate(struct ata_host *host) ...@@ -315,24 +282,18 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_associate_ide_port(ap); ata_acpi_associate_ide_port(ap);
if (ap->acpi_handle) { if (ap->acpi_handle) {
acpi_install_notify_handler(ap->acpi_handle,
ACPI_SYSTEM_NOTIFY,
ata_acpi_ap_notify, ap);
/* we might be on a docking station */ /* we might be on a docking station */
register_hotplug_dock_device(ap->acpi_handle, 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++) { for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
struct ata_device *dev = &ap->link.device[j]; struct ata_device *dev = &ap->link.device[j];
if (dev->acpi_handle) { if (dev->acpi_handle) {
acpi_install_notify_handler(dev->acpi_handle,
ACPI_SYSTEM_NOTIFY,
ata_acpi_dev_notify, dev);
/* we might be on a docking station */ /* we might be on a docking station */
register_hotplug_dock_device(dev->acpi_handle, register_hotplug_dock_device(dev->acpi_handle,
ata_acpi_dev_notify_dock, dev); &ata_acpi_dev_dock_ops, dev);
} }
} }
} }
......
...@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, ...@@ -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 */ /* callback routine to register each ACPI PCI slot object */
static acpi_status static acpi_status
...@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
*/ */
newfunc->flags &= ~FUNC_HAS_EJ0; newfunc->flags &= ~FUNC_HAS_EJ0;
if (register_hotplug_dock_device(handle, if (register_hotplug_dock_device(handle,
handle_hotplug_event_func, newfunc)) &acpiphp_dock_ops, newfunc))
dbg("failed to register dock device\n"); dbg("failed to register dock device\n");
/* we need to be notified when dock events happen /* we need to be notified when dock events happen
......
...@@ -327,6 +327,9 @@ int acpi_bus_get_private_data(acpi_handle, void **); ...@@ -327,6 +327,9 @@ int acpi_bus_get_private_data(acpi_handle, void **);
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
extern int register_acpi_notifier(struct notifier_block *); extern int register_acpi_notifier(struct notifier_block *);
extern int unregister_acpi_notifier(struct notifier_block *); extern int unregister_acpi_notifier(struct notifier_block *);
extern int register_acpi_bus_notifier(struct notifier_block *nb);
extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
/* /*
* External Functions * External Functions
*/ */
......
...@@ -116,12 +116,17 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type); ...@@ -116,12 +116,17 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Dock Station Dock Station
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
struct acpi_dock_ops {
acpi_notify_handler handler;
acpi_notify_handler uevent;
};
#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) #if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
extern int is_dock_device(acpi_handle handle); extern int is_dock_device(acpi_handle handle);
extern int register_dock_notifier(struct notifier_block *nb); extern int register_dock_notifier(struct notifier_block *nb);
extern void unregister_dock_notifier(struct notifier_block *nb); extern void unregister_dock_notifier(struct notifier_block *nb);
extern int register_hotplug_dock_device(acpi_handle handle, extern int register_hotplug_dock_device(acpi_handle handle,
acpi_notify_handler handler, struct acpi_dock_ops *ops,
void *context); void *context);
extern void unregister_hotplug_dock_device(acpi_handle handle); extern void unregister_hotplug_dock_device(acpi_handle handle);
#else #else
...@@ -137,7 +142,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb) ...@@ -137,7 +142,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
{ {
} }
static inline int register_hotplug_dock_device(acpi_handle handle, static inline int register_hotplug_dock_device(acpi_handle handle,
acpi_notify_handler handler, struct acpi_dock_ops *ops,
void *context) void *context)
{ {
return -ENODEV; return -ENODEV;
......
...@@ -193,6 +193,9 @@ acpi_status ...@@ -193,6 +193,9 @@ acpi_status
acpi_os_execute(acpi_execute_type type, acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context); acpi_osd_exec_callback function, void *context);
acpi_status
acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
void acpi_os_wait_events_complete(void *context); void acpi_os_wait_events_complete(void *context);
void acpi_os_sleep(acpi_integer milliseconds); void acpi_os_sleep(acpi_integer milliseconds);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment