drivers/platform/surface/surface_aggregator_hub.c

Source file repositories/reference/linux-study-clean/drivers/platform/surface/surface_aggregator_hub.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/surface/surface_aggregator_hub.c
Extension
.c
Size
9981 bytes
Lines
372
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ssam_hub_ops {
	int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state);
};

struct ssam_hub {
	struct ssam_device *sdev;

	enum ssam_hub_state state;
	unsigned long flags;

	struct delayed_work update_work;
	unsigned long connect_delay;

	struct ssam_event_notifier notif;
	struct ssam_hub_ops ops;
};

struct ssam_hub_desc {
	struct {
		struct ssam_event_registry reg;
		struct ssam_event_id id;
		enum ssam_event_mask mask;
	} event;

	struct {
		u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event);
		int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state);
	} ops;

	unsigned long connect_delay_ms;
};

static void 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);
}

static int ssam_hub_mark_hot_removed(struct device *dev, void *_data)
{
	struct ssam_device *sdev = to_ssam_device(dev);

	if (is_ssam_device(dev))
		ssam_device_mark_hot_removed(sdev);

	return 0;

Annotation

Implementation Notes