// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Surface System Aggregator Module (SSAM) subsystem device hubs. * * Provides a driver for SSAM subsystems device hubs. This driver performs * instantiation of the devices managed by said hubs and takes care of * (hot-)removal. * * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
staticvoid ssam_hub_update_workfn(struct work_struct *work)
{ struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work); enum ssam_hub_state state; int status = 0;
status = hub->ops.get_state(hub, &state); if (status) return;
/* * There is a small possibility that hub devices were hot-removed and * re-added before we were able to remove them here. In that case, both * the state returned by get_state() and the state of the hub will * equal SSAM_HUB_CONNECTED and we would bail early below, which would * leave child devices without proper (re-)initialization and the * hot-remove flag set. * * Therefore, we check whether devices have been hot-removed via an * additional flag on the hub and, in this case, override the returned * hub state. In case of a missed disconnect (i.e. get_state returned * "connected"), we further need to re-schedule this work (with the * appropriate delay) as the actual connect work submission might have * been merged with this one. * * This then leads to one of two cases: Either we submit an unnecessary * work item (which will get ignored via either the queue or the state * checks) or, in the unlikely case that the work is actually required, * double the normal connect delay.
*/ if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) { if (state == SSAM_HUB_CONNECTED)
schedule_delayed_work(&hub->update_work, hub->connect_delay);
state = SSAM_HUB_DISCONNECTED;
}
if (hub->state == state) return;
hub->state = state;
if (hub->state == SSAM_HUB_CONNECTED)
status = ssam_device_register_clients(hub->sdev); else
ssam_remove_clients(&hub->sdev->dev);
if (status)
dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status);
}
/* Mark devices as hot-removed before we remove any. */ if (!connected) {
set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags);
device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed);
}
/* * Delay update when the base/keyboard cover is being connected to give * devices/EC some time to set up.
*/
delay = connected ? hub->connect_delay : 0;
/* * Some devices (especially battery) may need a bit of time to be fully usable * after being (re-)connected. This delay has been determined via * experimentation.
*/ #define SSAM_BASE_UPDATE_CONNECT_DELAY 2500
/* * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and * consumed by the detachment system driver. We're just a (more or less) * silent observer.
*/ return 0;
}
/* * Some devices may need a bit of time to be fully usable after being * (re-)connected. This delay has been determined via experimentation.
*/ #define SSAM_KIP_UPDATE_CONNECT_DELAY 250
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.