struct list_head list;
struct list_head hotplug_list;
acpi_handle handle;
- acpi_notify_handler handler;
+ struct acpi_dock_ops *ops;
void *context;
};
* 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);
}
/*
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");
* 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);
}
/**
arg.integer.value = dock;
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
- printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
- (char *)name_buffer.pointer);
+ ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute"
+ " _DCK\n", (char *)name_buffer.pointer));
+
kfree(buffer.pointer);
kfree(name_buffer.pointer);
}
/**
* 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
* 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;
struct dock_station *dock_station;
+ int ret = -EINVAL;
if (!dock_station_count)
return -ENODEV;
* this would include the dock station itself
*/
list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ /*
+ * An ATA bay can be in a dock and itself can be ejected
+ * seperately, so there are two 'dock stations' which need the
+ * ops
+ */
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;
+ ret = 0;
}
}
- return -EINVAL;
+ return ret;
}
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
/* Fall back */
case ACPI_NOTIFY_EJECT_REQUEST:
begin_undock(ds);
- if (immediate_undock || surprise_removal)
+ if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
+ || surprise_removal)
handle_eject_request(ds, event);
else
dock_event(ds, event, UNDOCK_EVENT);
}
}
+struct dock_data {
+ acpi_handle handle;
+ unsigned long event;
+ struct dock_station *ds;
+};
+
+static void acpi_dock_deferred_cb(void *context)
+{
+ struct dock_data *data = (struct dock_data *)context;
+
+ dock_notify(data->handle, data->event, data->ds);
+ kfree(data);
+}
+
+static int acpi_dock_notifier_call(struct notifier_block *this,
+ unsigned long event, void *data)
+{
+ struct dock_station *dock_station;
+ acpi_handle handle = (acpi_handle)data;
+
+ if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
+ && event != ACPI_NOTIFY_EJECT_REQUEST)
+ return 0;
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
+ if (dock_station->handle == handle) {
+ struct dock_data *dock_data;
+
+ dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
+ if (!dock_data)
+ return 0;
+ dock_data->handle = handle;
+ dock_data->event = event;
+ dock_data->ds = dock_station;
+ acpi_os_hotplug_execute(acpi_dock_deferred_cb,
+ dock_data);
+ return 0 ;
+ }
+ }
+ 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
}
static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+static ssize_t show_dock_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dock_station *dock_station = *((struct dock_station **)
+ dev->platform_data);
+ char *type;
+
+ if (dock_station->flags & DOCK_IS_DOCK)
+ type = "dock_station";
+ else if (dock_station->flags & DOCK_IS_ATA)
+ type = "ata_bay";
+ else if (dock_station->flags & DOCK_IS_BAT)
+ type = "battery_bay";
+ else
+ type = "unknown";
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", type);
+}
+static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
+
/**
* dock_add - add a new dock station
* @handle: the dock station handle
static int dock_add(acpi_handle handle)
{
int ret;
- acpi_status status;
struct dock_dependent_device *dd;
struct dock_station *dock_station;
struct platform_device *dock_device;
dock_station = NULL;
return ret;
}
+ ret = device_create_file(&dock_device->dev, &dev_attr_type);
+ if (ret)
+ printk(KERN_ERR"Error %d adding sysfs file\n", ret);
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
}
add_dock_dependent_device(dock_station, dd);
- /* register for dock events */
- status = acpi_install_notify_handler(dock_station->handle,
- ACPI_SYSTEM_NOTIFY,
- dock_notify, dock_station);
-
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error installing notify handler\n");
- ret = -ENODEV;
- goto dock_add_err;
- }
-
dock_station_count++;
list_add(&dock_station->sibiling, &dock_stations);
return 0;
-dock_add_err:
- kfree(dd);
dock_add_err_unregister:
+ device_remove_file(&dock_device->dev, &dev_attr_type);
device_remove_file(&dock_device->dev, &dev_attr_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid);
static int dock_remove(struct dock_station *dock_station)
{
struct dock_dependent_device *dd, *tmp;
- acpi_status status;
struct platform_device *dock_device = dock_station->dock_device;
if (!dock_station_count)
list)
kfree(dd);
- /* remove dock notify handler */
- status = acpi_remove_notify_handler(dock_station->handle,
- ACPI_SYSTEM_NOTIFY,
- dock_notify);
- if (ACPI_FAILURE(status))
- printk(KERN_ERR "Error removing notify handler\n");
-
/* cleanup sysfs */
+ device_remove_file(&dock_device->dev, &dev_attr_type);
device_remove_file(&dock_device->dev, &dev_attr_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid);
static acpi_status
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
{
- /* If bay is in a dock, it's already handled */
- if (is_ejectable_bay(handle) && !is_dock_device(handle))
+ /* If bay is a dock, it's already handled */
+ if (is_ejectable_bay(handle) && !is_dock(handle))
dock_add(handle);
return AE_OK;
}
return 0;
}
+ register_acpi_bus_notifier(&dock_acpi_notifier);
printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
return 0;
{
struct dock_station *dock_station;
+ unregister_acpi_bus_notifier(&dock_acpi_notifier);
list_for_each_entry(dock_station, &dock_stations, sibiling)
dock_remove(dock_station);
}