drivers/usb/typec/mode_selection.c

Source file repositories/reference/linux-study-clean/drivers/usb/typec/mode_selection.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/mode_selection.c
Extension
.c
Size
7730 bytes
Lines
284
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 mode_state {
	u16 svid;
	u8 priority;
	int error;
	struct list_head list;
};

/**
 * struct mode_selection - Manages the selection and state of Alternate Modes
 * @mode_list: Prioritized list of available Alternate Modes
 * @lock: Mutex to protect mode_list
 * @work: Work structure
 * @partner: Handle to the Type-C partner device
 * @active_svid: svid of currently active mode
 * @timeout: Timeout for a mode entry attempt, ms
 * @delay: Delay between mode entry/exit attempts, ms
 */
struct mode_selection {
	struct list_head mode_list;
	/* Protects the mode_list*/
	struct mutex lock;
	struct delayed_work work;
	struct typec_partner *partner;
	u16 active_svid;
	unsigned int timeout;
	unsigned int delay;
};

/**
 * struct mode_order - Mode activation tracking
 * @svid: Standard or Vendor ID of the Alternate Mode
 * @enter: Flag indicating if the driver is currently attempting to enter or
 * exit the mode
 * @result: Outcome of the attempt to activate the mode
 */
struct mode_order {
	u16 svid;
	int enter;
	int result;
};

static int activate_altmode(struct device *dev, void *data)
{
	if (is_typec_partner_altmode(dev)) {
		struct typec_altmode *alt = to_typec_altmode(dev);
		struct mode_order *order = (struct mode_order *)data;

		if (order->svid == alt->svid) {
			if (alt->ops && alt->ops->activate)
				order->result = alt->ops->activate(alt, order->enter);
			else
				order->result = -EOPNOTSUPP;
			return 1;
		}
	}
	return 0;
}

static int mode_selection_activate(struct mode_selection *sel,
				   const u16 svid, const int enter)

	__must_hold(&sel->lock)
{
	struct mode_order order = {.svid = svid, .enter = enter, .result = -ENODEV};

	/*
	 * The port driver may acquire its internal mutex during alternate mode
	 * activation. Since this is the same mutex that may be held during the
	 * execution of typec_altmode_state_update(), it is crucial to release
	 * sel->mutex before activation to avoid potential deadlock.
	 * Note that sel->mode_list must remain invariant throughout this unlocked
	 * interval.
	 */
	mutex_unlock(&sel->lock);
	device_for_each_child(&sel->partner->dev, &order, activate_altmode);
	mutex_lock(&sel->lock);

	return order.result;
}

static void mode_list_clean(struct mode_selection *sel)
{
	struct mode_state *ms, *tmp;

	list_for_each_entry_safe(ms, tmp, &sel->mode_list, list) {
		list_del(&ms->list);
		kfree(ms);
	}
}

Annotation

Implementation Notes