drivers/hid/intel-ish-hid/ishtp/loader.c

Source file repositories/reference/linux-study-clean/drivers/hid/intel-ish-hid/ishtp/loader.c

File Facts

System
Linux kernel
Corpus path
drivers/hid/intel-ish-hid/ishtp/loader.c
Extension
.c
Size
16801 bytes
Lines
487
Domain
Driver Families
Bucket
drivers/hid
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

if (dma_bufs[i]) {
			dma_addr = le64_to_cpu(fragment->fragment_tbl[i].ddr_adrs);
			dma_free_coherent(dev->devc, fragment_size, dma_bufs[i], dma_addr);
			dma_bufs[i] = NULL;
		}
	}
}

/**
 * prepare_dma_bufs() - Prepare the DMA buffer for transferring firmware fragments
 * @dev: The ISHTP device
 * @ish_fw: The ISH firmware
 * @fragment: The ISHTP firmware fragment descriptor
 * @dma_bufs: The array of DMA fragment buffers
 * @fragment_size: The size of a single DMA fragment
 * @fragment_count: Number of fragments
 *
 * Return: 0 on success, negative error code on failure
 */
static int prepare_dma_bufs(struct ishtp_device *dev,
			    const struct firmware *ish_fw,
			    struct loader_xfer_dma_fragment *fragment,
			    void **dma_bufs, u32 fragment_size, u32 fragment_count)
{
	dma_addr_t dma_addr;
	u32 offset = 0;
	u32 length;
	int i;

	for (i = 0; i < fragment_count && offset < ish_fw->size; i++) {
		dma_bufs[i] = dma_alloc_coherent(dev->devc, fragment_size, &dma_addr, GFP_KERNEL);
		if (!dma_bufs[i])
			return -ENOMEM;

		fragment->fragment_tbl[i].ddr_adrs = cpu_to_le64(dma_addr);
		length = clamp(ish_fw->size - offset, 0, fragment_size);
		fragment->fragment_tbl[i].length = cpu_to_le32(length);
		fragment->fragment_tbl[i].fw_off = cpu_to_le32(offset);
		memcpy(dma_bufs[i], ish_fw->data + offset, length);
		clflush_cache_range(dma_bufs[i], fragment_size);

		offset += length;
	}

	return 0;
}

/* Patterns with PRODUCT_FAMILY */
#define ISH_FW_FILE_VENDOR_FAMILY_NAME_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x_%08x.bin"
#define ISH_FW_FILE_VENDOR_FAMILY_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin"
#define ISH_FW_FILE_VENDOR_FAMILY_NAME_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin"
#define ISH_FW_FILE_VENDOR_FAMILY_FMT "intel/ish/ish_%s_%08x_%08x.bin"

#define ISH_FW_FILE_VENDOR_NAME_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin"
#define ISH_FW_FILE_VENDOR_SKU_FMT "intel/ish/ish_%s_%08x_%08x.bin"
#define ISH_FW_FILE_VENDOR_NAME_FMT "intel/ish/ish_%s_%08x_%08x.bin"
#define ISH_FW_FILE_VENDOR_FMT "intel/ish/ish_%s_%08x.bin"
#define ISH_FW_FILE_DEFAULT_FMT "intel/ish/ish_%s.bin"

#define ISH_FW_FILENAME_LEN_MAX 72

#define ISH_CRC_INIT (~0u)
#define ISH_CRC_XOROUT (~0u)

static int _request_ish_firmware(const struct firmware **firmware_p,
					const char *name, struct device *dev)
{
	int ret;

	dev_dbg(dev, "Try to load firmware: %s\n", name);
	ret = firmware_request_nowarn(firmware_p, name, dev);
	if (!ret)
		dev_info(dev, "load firmware: %s\n", name);

	return ret;
}

/**
 * request_ish_firmware() - Request and load the ISH firmware.
 * @firmware_p: Pointer to the firmware image.
 * @dev: Device for which firmware is being requested.
 *
 * This function attempts to load the Integrated Sensor Hub (ISH) firmware
 * for the given device in the following order, prioritizing custom firmware
 * with more precise matching patterns:
 *
 *   ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_FAMILY_CRC32)
 *   _$(PRODUCT_NAME_CRC32)_${PRODUCT_SKU_CRC32}.bin
 *
 *   ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_FAMILY_CRC32)_${PRODUCT_SKU_CRC32}.bin

Annotation

Implementation Notes