예제 #1
0
/** sqn_load_firmware - loads firmware to card
 *  @func: SDIO function, used to transfer data via SDIO interface,
 *         also used to obtain pointer to device structure.
 *
 *  But now the only work it does - is loading of bootstrapper to card,
 *  because firmware is supposed to be loaded by a userspace program.
 */
int sqn_load_firmware(struct sdio_func *func)
{
	int rv = 0;
	const struct firmware *fw = 0;
//Create a local firmware_name with path to replace original global firmware_name -- Tony Wu.
	const char *firmware_name = "../../../data/wimax/Boot.bin";

	struct sqn_sdio_card *sqn_card = sdio_get_drvdata(func);

	sqn_pr_enter();

	sqn_pr_info("trying to find bootloader image: \"%s\"\n", firmware_name);
	if ((rv = request_firmware(&fw, firmware_name, &func->dev)))
		goto out;

	if (SQN_1130 == sqn_card->version) {
		sdio_claim_host(func);

		/* properly setup registers for firmware loading */
		sqn_pr_dbg("setting up SQN_H_SDRAM_NO_EMR register\n");
		sdio_writeb(func, 0, SQN_H_SDRAM_NO_EMR, &rv);
		if (rv) {
			sdio_release_host(func);
			goto out;
		}

		sqn_pr_dbg("setting up SQN_H_SDRAMCTL_RSTN register\n");
		sdio_writeb(func, 1, SQN_H_SDRAMCTL_RSTN, &rv);
		sdio_release_host(func);
		if (rv)
			goto out;
	}

	sqn_pr_info("loading bootloader to the card...\n");
	if ((rv = sqn_load_bootstrapper(func, (u8*) fw->data, fw->size)))
		goto out;

	/* boot the card */
	sqn_pr_info("bootting the card...\n");
	sdio_claim_host(func); // by daniel
	sdio_writeb(func, 1, SQN_H_CRSTN, &rv);
	sdio_release_host(func); // by daniel
	if (rv)
		goto out;
	sqn_pr_info("  done\n");

out:
	// To avoid kzalloc leakage in /drivers/base/firmware_class.c	
	if (fw) {
		release_firmware(fw);
		fw = NULL;
	}

	sqn_pr_leave();
	return rv;
}
예제 #2
0
/** sqn_load_bootstrapper - reads a binary boostrapper file, analize it
 *  and loads data to the card.
 *
 *  Bootstrapper is consists of Tag, Length, Value (TLV) sections.
 *  Each section starts with 4 bytes tag. Then goes length of data (4 bytes)
 *  and then the data itself.
 *
 *  All fields of bootstrapper file is in BIG ENDIAN format.
 */
static int sqn_load_bootstrapper(struct sdio_func *func, u8 *data, int size)
{
	struct sqn_tlv *tlv = (struct sqn_tlv*) data;
	int rv = 0;

	sqn_pr_enter();

	while (size > 0) {
		/*
		 * Convert values accordingly to platform "endianes"
		 * (big or little endian) because bootstrapper file
		 * data is big endian
		 */
		tlv->tag = be32_to_cpu(tlv->tag);
		tlv->length = be32_to_cpu(tlv->length);

		switch (tlv->tag) {
		case SWM_INFO_TAG_SQN_ROOT:
		case SWM_INFO_TAG_SQN_BOOTROM_GROUP:
		case SWM_INFO_TAG_SQN_ID_GROUP:
			/*
			 * This tag is a "container" tag - it's value field
			 * contains other tags
			 */

			/* sqn_pr_dbg("========================================\n"); */
			sqn_pr_dbg("tag: CONTAINER %x length: %u\n", tlv->tag
				, tlv->length);
			/* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */

			/*
			 * If this is a buggy tag, adjust length to
			 * the rest of data
			 */
			if (0 == tlv->length)
				tlv->length = size - sizeof(*tlv);

			rv = sqn_load_bootstrapper(func, (u8*) tlv->value
				, tlv->length);
			if (rv)
				goto out;
			break;

		case SWM_INFO_TAG_SQN_MEMCPY:
			/* sqn_pr_dbg("========================================\n"); */
			sqn_pr_dbg("tag: SWM_INFO_TAG_SQN_MEMCPY length: %u\n"
					, tlv->length);
			/* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */
			rv = sqn_handle_memcpy_tag(func
				, (struct sqn_tag_memcpy*) tlv->value);
			if (rv)
				goto out;
			break;

		case SWM_INFO_TAG_SQN_MEMSET:
			/* sqn_pr_dbg("========================================\n"); */
			sqn_pr_dbg("tag: SWM_INFO_TAG_SQN_MEMSET length: %u\n"
					, tlv->length);
			/* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */
			rv = sqn_handle_memset_tag(func
				, (struct sqn_tag_memset*) tlv->value);
			if (rv)
				goto out;
			break;

		case SWM_INFO_TAG_SQN_MAC_ADDRESS:
			/* sqn_pr_dbg("========================================\n"); */
			sqn_pr_dbg("tag: SWM_INFO_TAG_SQN_MAC_ADDRESS length: %u\n"
					, tlv->length);
			/* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */

			rv = sqn_handle_mac_addr_tag(func, tlv->value
				, tlv->length);
			if (rv)
				goto out;
			break;

		default:
			/* skip all other tags */
			/* sqn_pr_dbg("========================================\n"); */
			sqn_pr_dbg("tag: UNKNOWN %x length: %u\n"
					, tlv->tag, tlv->length);
			/* sqn_pr_dbg_dump("|", tlv->value, tlv->length); */
			break;
		}

		/* increment tlv to point it to the beginning of the next
		 * sqn_tlv struct and decrement size accordingly
		 */
		size = (int)(size - (sizeof(*tlv) + tlv->length));
		tlv = (struct sqn_tlv*) ((u8*)tlv + sizeof(*tlv) + tlv->length);
	}

	if (0 != size) {
		/* something wrong with parsing of tlv values */
		rv = -1;
		goto out;
	}

out:
	sqn_pr_leave();
	return rv;
}