drivers/staging/greybus/bootrom.c

Source file repositories/reference/linux-study-clean/drivers/staging/greybus/bootrom.c

File Facts

System
Linux kernel
Corpus path
drivers/staging/greybus/bootrom.c
Extension
.c
Size
13608 bytes
Lines
527
Domain
Driver Families
Bucket
drivers/staging
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 gb_bootrom {
	struct gb_connection	*connection;
	const struct firmware	*fw;
	u8			protocol_major;
	u8			protocol_minor;
	enum next_request_type	next_request;
	struct delayed_work	dwork;
	struct mutex		mutex; /* Protects bootrom->fw */
};

static void free_firmware(struct gb_bootrom *bootrom)
{
	if (!bootrom->fw)
		return;

	release_firmware(bootrom->fw);
	bootrom->fw = NULL;
}

static void gb_bootrom_timedout(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct gb_bootrom *bootrom = container_of(dwork,
						  struct gb_bootrom, dwork);
	struct device *dev = &bootrom->connection->bundle->dev;
	const char *reason;

	switch (bootrom->next_request) {
	case NEXT_REQ_FIRMWARE_SIZE:
		reason = "Firmware Size Request";
		break;
	case NEXT_REQ_GET_FIRMWARE:
		reason = "Get Firmware Request";
		break;
	case NEXT_REQ_READY_TO_BOOT:
		reason = "Ready to Boot Request";
		break;
	case NEXT_REQ_MODE_SWITCH:
		reason = "Interface Mode Switch";
		break;
	default:
		reason = NULL;
		dev_err(dev, "Invalid next-request: %u", bootrom->next_request);
		break;
	}

	dev_err(dev, "Timed out waiting for %s from the Module\n", reason);

	mutex_lock(&bootrom->mutex);
	free_firmware(bootrom);
	mutex_unlock(&bootrom->mutex);

	/* TODO: Power-off Module ? */
}

static void gb_bootrom_set_timeout(struct gb_bootrom *bootrom,
				   enum next_request_type next,
				   unsigned long timeout)
{
	bootrom->next_request = next;
	schedule_delayed_work(&bootrom->dwork, msecs_to_jiffies(timeout));
}

static void gb_bootrom_cancel_timeout(struct gb_bootrom *bootrom)
{
	cancel_delayed_work_sync(&bootrom->dwork);
}

/*
 * The es2 chip doesn't have VID/PID programmed into the hardware and we need to
 * hack that up to distinguish different modules and their firmware blobs.
 *
 * This fetches VID/PID (over bootrom protocol) for es2 chip only, when VID/PID
 * already sent during hotplug are 0.
 *
 * Otherwise, we keep intf->vendor_id/product_id same as what's passed
 * during hotplug.
 */
static void bootrom_es2_fixup_vid_pid(struct gb_bootrom *bootrom)
{
	struct gb_bootrom_get_vid_pid_response response;
	struct gb_connection *connection = bootrom->connection;
	struct gb_interface *intf = connection->bundle->intf;
	int ret;

	if (!(intf->quirks & GB_INTERFACE_QUIRK_NO_GMP_IDS))
		return;

	ret = gb_operation_sync(connection, GB_BOOTROM_TYPE_GET_VID_PID,
				NULL, 0, &response, sizeof(response));

Annotation

Implementation Notes