staticbool immediate_undock = 1;
module_param(immediate_undock, bool, 0644);
MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " "undock immediately when the undock button is pressed, 0 will cause" " the driver to wait for userspace to write the undock sysfs file " " before undocking");
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 * @adev: ACPI device object to find. * * iterate over the dependent device list for this dock. If the * dependent device matches the handle, return.
*/ staticstruct dock_dependent_device *
find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
{ struct dock_dependent_device *dd;
list_for_each_entry(dd, &ds->dependent_devices, list) if (adev == dd->adev) return dd;
if (ds && !find_dock_dependent_device(ds, adev))
add_dock_dependent_device(ds, adev);
}
/***************************************************************************** * Dock functions *
*****************************************************************************/
/** * is_dock_device - see if a device is on a dock station * @adev: ACPI device object to check. * * If this device is either the dock station itself, * or is a device dependent on the dock station, then it * is a dock device
*/ int is_dock_device(struct acpi_device *adev)
{ struct dock_station *dock_station;
if (!dock_station_count) return 0;
if (acpi_dock_match(adev->handle)) return 1;
list_for_each_entry(dock_station, &dock_stations, sibling) if (find_dock_dependent_device(dock_station, adev)) return 1;
return 0;
}
EXPORT_SYMBOL_GPL(is_dock_device);
/** * dock_present - see if the dock station is present. * @ds: the dock station * * execute the _STA method. note that present does not * imply that we are docked.
*/ staticint dock_present(struct dock_station *ds)
{ unsignedlonglong sta;
acpi_status status;
if (ds) {
status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta); if (ACPI_SUCCESS(status) && sta) return 1;
} return 0;
}
/** * hot_remove_dock_devices - Remove dock station devices. * @ds: Dock station.
*/ staticvoid 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,
DOCK_CALL_HANDLER);
/** * hotplug_dock_devices - Insert devices on a dock station. * @ds: the dock station * @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. * Traverse the list of dock devices that have registered a * hotplug handler, and call the handler.
*/ staticvoid hotplug_dock_devices(struct dock_station *ds, u32 event)
{ struct dock_dependent_device *dd;
/* * Check if all devices have been enumerated already. If not, run * acpi_bus_scan() for them and 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) { struct acpi_device *adev = dd->adev;
if (!acpi_device_enumerated(adev)) { int ret = acpi_bus_scan(adev->handle);
if (ret)
dev_dbg(&adev->dev, "scan error %d\n", -ret);
}
}
}
if (num != DOCK_EVENT)
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
/** * handle_dock - handle a dock event * @ds: the dock station * @dock: to dock, or undock - that is the question * * Execute the _DCK method in response to an acpi event
*/ staticvoid handle_dock(struct dock_station *ds, int dock)
{
acpi_status status; struct acpi_object_list arg_list; union acpi_object arg; unsignedlonglong value;
acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
/* _DCK method has one argument */
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = dock;
status = acpi_evaluate_integer(ds->handle, "_DCK", &arg_list, &value); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
status);
}
/** * dock_in_progress - see if we are in the middle of handling a dock event * @ds: the dock station * * Sometimes while docking, false dock events can be sent to the driver * because good connections aren't made or some other reason. Ignore these * if we are in the middle of doing something.
*/ staticint dock_in_progress(struct dock_station *ds)
{ if ((ds->flags & DOCK_DOCKING) ||
time_before(jiffies, (ds->last_dock_time + HZ))) return 1; return 0;
}
/** * handle_eject_request - handle an undock request checking for error conditions * @ds: The dock station to undock. * @event: The ACPI event number associated with the undock request. * * Check to make sure the dock device is still present, then undock and * hotremove all the devices that may need removing.
*/ staticint handle_eject_request(struct dock_station *ds, u32 event)
{ if (dock_in_progress(ds)) return -EBUSY;
/* * here we need to generate the undock * event prior to actually doing the undock * so that the device struct still exists. * Also, even send the dock event if the * device is not present anymore
*/
dock_event(ds, event, UNDOCK_EVENT);
hot_remove_dock_devices(ds);
undock(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;
}
complete_undock(ds); return 0;
}
/** * 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.
*/ int dock_notify(struct acpi_device *adev, u32 event)
{
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 * request.
*/ if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
event = ACPI_NOTIFY_EJECT_REQUEST;
/* * dock station: BUS_CHECK - docked or surprise removal * DEVICE_CHECK - undocked * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal * * To simplify event handling, dock dependent device handler always * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and * ACPI_NOTIFY_EJECT_REQUEST for removal
*/ switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
begin_dock(ds);
dock(ds); if (!dock_present(ds)) {
acpi_handle_err(handle, "Unable to dock!\n");
complete_dock(ds); break;
}
hotplug_dock_devices(ds, event);
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
acpi_evaluate_lck(ds->handle, 1);
acpi_update_all_gpes(); break;
} if (dock_present(ds) || dock_in_progress(ds)) break; /* This is a surprise removal */
surprise_removal = 1;
event = ACPI_NOTIFY_EJECT_REQUEST; /* Fall back */
fallthrough; case ACPI_NOTIFY_EJECT_REQUEST:
begin_undock(ds); if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
|| surprise_removal)
handle_eject_request(ds, event); else
dock_event(ds, event, UNDOCK_EVENT); break;
} return 0;
}
if (dock_station->flags & DOCK_IS_DOCK)
type = "dock_station"; elseif (dock_station->flags & DOCK_IS_ATA)
type = "ata_bay"; elseif (dock_station->flags & DOCK_IS_BAT)
type = "battery_bay"; else
type = "unknown";
/** * acpi_dock_add - Add a new dock station * @adev: Dock station ACPI device object. * * allocated and initialize a new dock station device.
*/ void acpi_dock_add(struct acpi_device *adev)
{ struct dock_station *dock_station, ds = { NULL, }; struct platform_device_info pdevinfo;
acpi_handle handle = adev->handle; struct platform_device *dd; int ret;
/* we want the dock device to send uevents */
dev_set_uevent_suppress(&dd->dev, 0);
if (acpi_dock_match(handle))
dock_station->flags |= DOCK_IS_DOCK; if (acpi_ata_match(handle))
dock_station->flags |= DOCK_IS_ATA; if (acpi_device_is_battery(adev))
dock_station->flags |= DOCK_IS_BAT;
ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); if (ret) goto err_unregister;
/* add the dock station as a device dependent on itself */
ret = add_dock_dependent_device(dock_station, adev); if (ret) goto err_rmgroup;
dock_station_count++;
list_add(&dock_station->sibling, &dock_stations);
adev->flags.is_dock_station = true;
dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
dock_station_count); return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.