static int qca_download_firmware()

in btqca.c [445:530]


static int qca_download_firmware(struct hci_dev *hdev,
				 struct qca_fw_config *config,
				 enum qca_btsoc_type soc_type,
				 u8 rom_ver)
{
	const struct firmware *fw;
	u8 *data;
	const u8 *segment;
	int ret, size, remain, i = 0;

	bt_dev_info(hdev, "QCA Downloading %s", config->fwname);

	ret = request_firmware(&fw, config->fwname, &hdev->dev);
	if (ret) {
		/* For WCN6750, if mbn file is not present then check for
		 * tlv file.
		 */
		if (soc_type == QCA_WCN6750 && config->type == ELF_TYPE_PATCH) {
			bt_dev_dbg(hdev, "QCA Failed to request file: %s (%d)",
				   config->fwname, ret);
			config->type = TLV_TYPE_PATCH;
			snprintf(config->fwname, sizeof(config->fwname),
				 "qca/msbtfw%02x.tlv", rom_ver);
			bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
			ret = request_firmware(&fw, config->fwname, &hdev->dev);
			if (ret) {
				bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
					   config->fwname, ret);
				return ret;
			}
		} else {
			bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
				   config->fwname, ret);
			return ret;
		}
	}

	size = fw->size;
	data = vmalloc(fw->size);
	if (!data) {
		bt_dev_err(hdev, "QCA Failed to allocate memory for file: %s",
			   config->fwname);
		release_firmware(fw);
		return -ENOMEM;
	}

	memcpy(data, fw->data, size);
	release_firmware(fw);

	qca_tlv_check_data(hdev, config, data, soc_type);

	segment = data;
	remain = size;
	while (remain > 0) {
		int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain);

		bt_dev_dbg(hdev, "Send segment %d, size %d", i++, segsize);

		remain -= segsize;
		/* The last segment is always acked regardless download mode */
		if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT)
			config->dnld_mode = QCA_SKIP_EVT_NONE;

		ret = qca_tlv_send_segment(hdev, segsize, segment,
					   config->dnld_mode, soc_type);
		if (ret)
			goto out;

		segment += segsize;
	}

	/* Latest qualcomm chipsets are not sending a command complete event
	 * for every fw packet sent. They only respond with a vendor specific
	 * event for the last packet. This optimization in the chip will
	 * decrease the BT in initialization time. Here we will inject a command
	 * complete event to avoid a command timeout error message.
	 */
	if (config->dnld_type == QCA_SKIP_EVT_VSE_CC ||
	    config->dnld_type == QCA_SKIP_EVT_VSE)
		ret = qca_inject_cmd_complete_event(hdev);

out:
	vfree(data);

	return ret;
}