Skip to content

Commit aa4674c

Browse files
lixuzhaJiri Kosina
authored andcommitted
hid: intel-ish-hid: Add support for vendor customized firmware loading
Enhance the firmware loader to support the loading of vendor-specific customized firmware for the Intel Integrated Sensor Hub (ISH). The loader now constructs firmware file names based on the DMI_SYS_VENDOR, DMI_PRODUCT_NAME, and DMI_PRODUCT_SKU information in Desktop Management Interface (DMI). The loader will attempt to load the firmware files following a specific naming convention in sequence. If successful, it will skip the remaining files. For more details, please refer to Documentation/hid/intel-ish-hid.rst. Signed-off-by: Zhang Lixu <[email protected]> Acked-by: Srinivas Pandruvada <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 6413615 commit aa4674c

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

drivers/hid/intel-ish-hid/ipc/pci-ish.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum ishtp_driver_data_index {
3131
#define ISH_FW_GEN_LNL_M "lnlm"
3232

3333
#define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
34+
#define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
3435

3536
static struct ishtp_driver_data ishtp_driver_data[] = {
3637
[ISHTP_DRIVER_DATA_LNL_M] = {
@@ -400,3 +401,4 @@ MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver");
400401
MODULE_LICENSE("GPL");
401402

402403
MODULE_FIRMWARE(ISH_FIRMWARE_PATH(ISH_FW_GEN_LNL_M));
404+
MODULE_FIRMWARE(ISH_FIRMWARE_PATH_ALL);

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

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535

3636
#include <linux/cacheflush.h>
3737
#include <linux/container_of.h>
38+
#include <linux/crc32.h>
3839
#include <linux/dev_printk.h>
3940
#include <linux/dma-mapping.h>
41+
#include <linux/dmi.h>
4042
#include <linux/errno.h>
4143
#include <linux/firmware.h>
4244
#include <linux/gfp_types.h>
@@ -193,21 +195,117 @@ static int prepare_dma_bufs(struct ishtp_device *dev,
193195
return 0;
194196
}
195197

198+
#define ISH_FW_FILE_VENDOR_NAME_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin"
199+
#define ISH_FW_FILE_VENDOR_SKU_FMT "intel/ish/ish_%s_%08x_%08x.bin"
200+
#define ISH_FW_FILE_VENDOR_NAME_FMT "intel/ish/ish_%s_%08x_%08x.bin"
201+
#define ISH_FW_FILE_VENDOR_FMT "intel/ish/ish_%s_%08x.bin"
196202
#define ISH_FW_FILE_DEFAULT_FMT "intel/ish/ish_%s.bin"
197203

198204
#define ISH_FW_FILENAME_LEN_MAX 56
199205

206+
#define ISH_CRC_INIT (~0u)
207+
#define ISH_CRC_XOROUT (~0u)
208+
209+
static int _request_ish_firmware(const struct firmware **firmware_p,
210+
const char *name, struct device *dev)
211+
{
212+
int ret;
213+
214+
dev_dbg(dev, "Try to load firmware: %s\n", name);
215+
ret = firmware_request_nowarn(firmware_p, name, dev);
216+
if (!ret)
217+
dev_info(dev, "load firmware: %s\n", name);
218+
219+
return ret;
220+
}
221+
222+
/**
223+
* request_ish_firmware() - Request and load the ISH firmware.
224+
* @firmware_p: Pointer to the firmware image.
225+
* @dev: Device for which firmware is being requested.
226+
*
227+
* This function attempts to load the Integrated Sensor Hub (ISH) firmware
228+
* for the given device in the following order, prioritizing custom firmware
229+
* with more precise matching patterns:
230+
*
231+
* ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_NAME_CRC32)_${PRODUCT_SKU_CRC32}.bin
232+
* ish_${fw_generation}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin
233+
* ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_NAME_CRC32).bin
234+
* ish_${fw_generation}_${SYS_VENDOR_CRC32}.bin
235+
* ish_${fw_generation}.bin
236+
*
237+
* The driver will load the first matching firmware and skip the rest. If no
238+
* matching firmware is found, it will proceed to the next pattern in the
239+
* specified order. If all searches fail, the default Intel firmware, listed
240+
* last in the order above, will be loaded.
241+
*
242+
* The firmware file name is constructed using CRC32 checksums of strings.
243+
* This is done to create a valid file name that does not contain spaces
244+
* or special characters which may be present in the original strings.
245+
*
246+
* The CRC-32 algorithm uses the following parameters:
247+
* Poly: 0x04C11DB7
248+
* Init: 0xFFFFFFFF
249+
* RefIn: true
250+
* RefOut: true
251+
* XorOut: 0xFFFFFFFF
252+
*
253+
* Return: 0 on success, negative error code on failure.
254+
*/
200255
static int request_ish_firmware(const struct firmware **firmware_p,
201256
struct device *dev)
202257
{
258+
const char *gen, *sys_vendor, *product_name, *product_sku;
203259
struct ishtp_device *ishtp = dev_get_drvdata(dev);
204-
const char *gen;
260+
u32 vendor_crc, name_crc, sku_crc;
205261
char filename[ISH_FW_FILENAME_LEN_MAX];
262+
int ret;
206263

207264
gen = ishtp->driver_data->fw_generation;
208-
snprintf(filename, sizeof(filename), ISH_FW_FILE_DEFAULT_FMT, gen);
265+
sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
266+
product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
267+
product_sku = dmi_get_system_info(DMI_PRODUCT_SKU);
268+
269+
if (sys_vendor)
270+
vendor_crc = crc32(ISH_CRC_INIT, sys_vendor, strlen(sys_vendor)) ^ ISH_CRC_XOROUT;
271+
if (product_name)
272+
name_crc = crc32(ISH_CRC_INIT, product_name, strlen(product_name)) ^ ISH_CRC_XOROUT;
273+
if (product_sku)
274+
sku_crc = crc32(ISH_CRC_INIT, product_sku, strlen(product_sku)) ^ ISH_CRC_XOROUT;
275+
276+
if (sys_vendor && product_name && product_sku) {
277+
snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_NAME_SKU_FMT, gen,
278+
vendor_crc, name_crc, sku_crc);
279+
ret = _request_ish_firmware(firmware_p, filename, dev);
280+
if (!ret)
281+
return 0;
282+
}
283+
284+
if (sys_vendor && product_sku) {
285+
snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_SKU_FMT, gen, vendor_crc,
286+
sku_crc);
287+
ret = _request_ish_firmware(firmware_p, filename, dev);
288+
if (!ret)
289+
return 0;
290+
}
209291

210-
return request_firmware(firmware_p, filename, dev);
292+
if (sys_vendor && product_name) {
293+
snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_NAME_FMT, gen, vendor_crc,
294+
name_crc);
295+
ret = _request_ish_firmware(firmware_p, filename, dev);
296+
if (!ret)
297+
return 0;
298+
}
299+
300+
if (sys_vendor) {
301+
snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_FMT, gen, vendor_crc);
302+
ret = _request_ish_firmware(firmware_p, filename, dev);
303+
if (!ret)
304+
return 0;
305+
}
306+
307+
snprintf(filename, sizeof(filename), ISH_FW_FILE_DEFAULT_FMT, gen);
308+
return _request_ish_firmware(firmware_p, filename, dev);
211309
}
212310

213311
/**

0 commit comments

Comments
 (0)