drivers/usb/typec/altmodes/thunderbolt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/altmodes/thunderbolt.c
Extension
.c
Size
8943 bytes
Lines
389
Domain
Driver Families
Bucket
drivers/usb
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 tbt_altmode {
	enum tbt_state state;
	struct typec_cable *cable;
	struct typec_altmode *alt;
	struct typec_altmode *plug[2];
	u32 enter_vdo;

	struct work_struct work;
	struct mutex lock; /* device lock */
};

static bool tbt_ready(struct typec_altmode *alt);

static int tbt_enter_mode(struct tbt_altmode *tbt)
{
	return typec_altmode_enter(tbt->alt, &tbt->enter_vdo);
}

static void tbt_altmode_work(struct work_struct *work)
{
	struct tbt_altmode *tbt = container_of(work, struct tbt_altmode, work);
	int ret;

	mutex_lock(&tbt->lock);

	switch (tbt->state) {
	case TBT_STATE_SOP_P_ENTER:
		ret = typec_cable_altmode_enter(tbt->alt, TYPEC_PLUG_SOP_P, NULL);
		if (ret) {
			dev_dbg(&tbt->plug[TYPEC_PLUG_SOP_P]->dev,
				"failed to enter mode (%d)\n", ret);
			goto disable_plugs;
		}
		break;
	case TBT_STATE_SOP_PP_ENTER:
		ret = typec_cable_altmode_enter(tbt->alt, TYPEC_PLUG_SOP_PP,  NULL);
		if (ret) {
			dev_dbg(&tbt->plug[TYPEC_PLUG_SOP_PP]->dev,
				"failed to enter mode (%d)\n", ret);
			goto disable_plugs;
		}
		break;
	case TBT_STATE_ENTER:
		ret = tbt_enter_mode(tbt);
		if (ret)
			dev_dbg(&tbt->alt->dev, "failed to enter mode (%d)\n",
				ret);
		break;
	case TBT_STATE_EXIT:
		typec_altmode_exit(tbt->alt);
		break;
	case TBT_STATE_SOP_PP_EXIT:
		typec_cable_altmode_exit(tbt->alt, TYPEC_PLUG_SOP_PP);
		break;
	case TBT_STATE_SOP_P_EXIT:
		typec_cable_altmode_exit(tbt->alt, TYPEC_PLUG_SOP_P);
		break;
	default:
		break;
	}

	tbt->state = TBT_STATE_IDLE;

	mutex_unlock(&tbt->lock);
	return;

disable_plugs:
	for (int i = TYPEC_PLUG_SOP_PP; i >= 0; --i) {
		if (tbt->plug[i])
			typec_altmode_put_plug(tbt->plug[i]);

		tbt->plug[i] = NULL;
	}

	tbt->state = TBT_STATE_ENTER;
	schedule_work(&tbt->work);
	mutex_unlock(&tbt->lock);
}

/*
 * If SOP' is available, enter that first (which will trigger a VDM response
 * that will enter SOP" if available and then the port). If entering SOP' fails,
 * stop attempting to enter either cable altmode (probably not supported) and
 * directly enter the port altmode.
 */
static int tbt_enter_modes_ordered(struct typec_altmode *alt)
{
	struct tbt_altmode *tbt = typec_altmode_get_drvdata(alt);
	int ret = 0;

Annotation

Implementation Notes