brcmfmac: introduce brcmf_fw_alloc_request() function

The function brcmf_fw_alloc_request() takes a list of required files
and allocated the struct brcmf_fw_request instance accordingly. The
request can be modified by the caller before being passed to the
brcmf_fw_request_firmwares() function.

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
index 95004db..f495d22 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -688,3 +688,61 @@ int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
 	return 0;
 }
 
+struct brcmf_fw_request *
+brcmf_fw_alloc_request(u32 chip, u32 chiprev,
+		       struct brcmf_firmware_mapping mapping_table[],
+		       u32 table_size, struct brcmf_fw_name *fwnames,
+		       u32 n_fwnames)
+{
+	struct brcmf_fw_request *fwreq;
+	char chipname[12];
+	const char *mp_path;
+	u32 i, j;
+	char end;
+	size_t reqsz;
+
+	for (i = 0; i < table_size; i++) {
+		if (mapping_table[i].chipid == chip &&
+		    mapping_table[i].revmask & BIT(chiprev))
+			break;
+	}
+
+	if (i == table_size) {
+		brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev);
+		return NULL;
+	}
+
+	reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item);
+	fwreq = kzalloc(reqsz, GFP_KERNEL);
+	if (!fwreq)
+		return NULL;
+
+	brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
+
+	brcmf_info("using %s for chip %s\n",
+		   mapping_table[i].fw_base, chipname);
+
+	mp_path = brcmf_mp_global.firmware_path;
+	end = mp_path[strlen(mp_path) - 1];
+	fwreq->n_items = n_fwnames;
+
+	for (j = 0; j < n_fwnames; j++) {
+		fwreq->items[j].path = fwnames[j].path;
+		/* check if firmware path is provided by module parameter */
+		if (brcmf_mp_global.firmware_path[0] != '\0') {
+			strlcpy(fwnames[j].path, mp_path,
+				BRCMF_FW_NAME_LEN);
+
+			if (end != '/') {
+				strlcat(fwnames[j].path, "/",
+					BRCMF_FW_NAME_LEN);
+			}
+		}
+		brcmf_fw_get_full_name(fwnames[j].path,
+				       mapping_table[i].fw_base,
+				       fwnames[j].extension);
+		fwreq->items[j].path = fwnames[j].path;
+	}
+
+	return fwreq;
+}