⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csr1212.c

📁 这是关于ieee1394的最新源码,上面包含了所有更新的部分!
💻 C
📖 第 1 页 / 共 3 页
字号:
int csr1212_generate_csr_image(struct csr1212_csr *csr){	struct csr1212_bus_info_block_img *bi;	struct csr1212_csr_rom_cache *cache;	struct csr1212_keyval *kv;	size_t agg_size;	int ret;	int init_offset;	if (!csr)		return CSR1212_EINVAL;	cache = csr->cache_head;	bi = (struct csr1212_bus_info_block_img*)cache->data;	bi->length = bytes_to_quads(csr->bus_info_len) - 1;	bi->crc_length = bi->length;	bi->crc = csr1212_crc16(bi->data, bi->crc_length);	csr->root_kv->next = NULL;	csr->root_kv->prev = NULL;	agg_size = csr1212_generate_layout_order(csr->root_kv);	init_offset = csr->bus_info_len;	for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {		if (!cache) {			/* Estimate approximate number of additional cache			 * regions needed (it assumes that the cache holding			 * the first 1K Config ROM space always exists). */			int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -						(2 * sizeof(u_int32_t))) + 1;			/* Add additional cache regions, extras will be			 * removed later */			for (; est_c; est_c--) {				ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);				if (ret != CSR1212_SUCCESS)					return ret;			}			/* Need to re-layout for additional cache regions */			agg_size = csr1212_generate_layout_order(csr->root_kv);			kv = csr->root_kv;			cache = csr->cache_head;			init_offset = csr->bus_info_len;		}		kv = csr1212_generate_positions(cache, kv, init_offset);		agg_size -= cache->len;		init_offset = sizeof(u_int32_t);	}	/* Remove unused, excess cache regions */	while (cache) {		struct csr1212_csr_rom_cache *oc = cache;		cache = cache->next;		csr1212_remove_cache(csr, oc);	}	/* Go through the list backward so that when done, the correct CRC	 * will be calculated for the Extended ROM areas. */	for(cache = csr->cache_tail; cache; cache = cache->prev) {		/* Only Extended ROM caches should have this set. */		if (cache->ext_rom) {			int leaf_size;			/* Make sure the Extended ROM leaf is a multiple of			 * max_rom in size. */			if (csr->max_rom < 1)				return CSR1212_EINVAL;			leaf_size = (cache->len + (csr->max_rom - 1)) &				~(csr->max_rom - 1);			/* Zero out the unused ROM region */			memset(cache->data + bytes_to_quads(cache->len), 0x00,			       leaf_size - cache->len);			/* Subtract leaf header */			leaf_size -= sizeof(u_int32_t);			/* Update the Extended ROM leaf length */			cache->ext_rom->value.leaf.len =				bytes_to_quads(leaf_size);		} else {			/* Zero out the unused ROM region */			memset(cache->data + bytes_to_quads(cache->len), 0x00,			       cache->size - cache->len);		}		/* Copy the data into the cache buffer */		csr1212_fill_cache(cache);		if (cache != csr->cache_head) {			/* Set the length and CRC of the extended ROM. */			struct csr1212_keyval_img *kvi =				(struct csr1212_keyval_img*)cache->data;			kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1);			kvi->crc = csr1212_crc16(kvi->data,						 bytes_to_quads(cache->len) - 1);		}	}	return CSR1212_SUCCESS;}int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len){	struct csr1212_csr_rom_cache *cache;	for (cache = csr->cache_head; cache; cache = cache->next) {		if (offset >= cache->offset &&		    (offset + len) <= (cache->offset + cache->size)) {			memcpy(buffer,			       &cache->data[bytes_to_quads(offset - cache->offset)],			       len);			return CSR1212_SUCCESS;		}	}	return CSR1212_ENOENT;}/* Parse a chunk of data as a Config ROM */static int csr1212_parse_bus_info_block(struct csr1212_csr *csr){	struct csr1212_bus_info_block_img *bi;	struct csr1212_cache_region *cr;	int i;	int ret;	/* IEEE 1212 says that the entire bus info block should be readable in	 * a single transaction regardless of the max_rom value.	 * Unfortunately, many IEEE 1394 devices do not abide by that, so the	 * bus info block will be read 1 quadlet at a time.  The rest of the	 * ConfigROM will be read according to the max_rom field. */	for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) {		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,					 sizeof(csr1212_quad_t),					 &csr->cache_head->data[bytes_to_quads(i)],					 csr->private);		if (ret != CSR1212_SUCCESS)			return ret;	}	bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;	csr->crc_len = quads_to_bytes(bi->crc_length);	/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not	 * always the case, so read the rest of the crc area 1 quadlet at a time. */	for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) {		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,					 sizeof(csr1212_quad_t),					 &csr->cache_head->data[bytes_to_quads(i)],					 csr->private);		if (ret != CSR1212_SUCCESS)			return ret;	}	if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length)		return CSR1212_EINVAL;#if 0	/* Apparently there are too many differnt wrong implementations of the	 * CRC algorithm that verifying them is moot. */	if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&	    (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))		return CSR1212_EINVAL;#endif	cr = CSR1212_MALLOC(sizeof(*cr));	if (!cr)		return CSR1212_ENOMEM;	cr->next = NULL;	cr->prev = NULL;	cr->offset_start = 0;	cr->offset_end = csr->crc_len + 4;	csr->cache_head->filled_head = cr;	csr->cache_head->filled_tail = cr;	return CSR1212_SUCCESS;}static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,				   csr1212_quad_t ki,				   u_int32_t kv_pos){	int ret = CSR1212_SUCCESS;	struct csr1212_keyval *k = NULL;	u_int32_t offset;	switch(CSR1212_KV_KEY_TYPE(ki)) {	case CSR1212_KV_TYPE_IMMEDIATE:		k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),					  CSR1212_KV_VAL(ki));		if (!k) {			ret = CSR1212_ENOMEM;			goto fail;		}		k->refcnt = 0;	/* Don't keep local reference when parsing. */		break;	case CSR1212_KV_TYPE_CSR_OFFSET:		k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),					   CSR1212_KV_VAL(ki));		if (!k) {			ret = CSR1212_ENOMEM;			goto fail;		}		k->refcnt = 0;	/* Don't keep local reference when parsing. */		break;	default:		/* Compute the offset from 0xffff f000 0000. */		offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;		if (offset == kv_pos) {			/* Uh-oh.  Can't have a relative offset of 0 for Leaves			 * or Directories.  The Config ROM image is most likely			 * messed up, so we'll just abort here. */			ret = CSR1212_EIO;			goto fail;		}		k = csr1212_find_keyval_offset(dir, offset);		if (k)			break;		/* Found it. */		if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {			k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));		} else {			k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);		}		if (!k) {			ret = CSR1212_ENOMEM;			goto fail;		}		k->refcnt = 0;	/* Don't keep local reference when parsing. */		k->valid = 0;	/* Contents not read yet so it's not valid. */		k->offset = offset;		k->prev = dir;		k->next = dir->next;		dir->next->prev = k;		dir->next = k;	}	ret = csr1212_attach_keyval_to_directory(dir, k);fail:	if (ret != CSR1212_SUCCESS) {		if (k)			free_keyval(k);	}	return ret;}int csr1212_parse_keyval(struct csr1212_keyval *kv,			 struct csr1212_csr_rom_cache *cache){	struct csr1212_keyval_img *kvi;	int i;	int ret = CSR1212_SUCCESS;	int kvi_len;	kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -								      cache->offset)];	kvi_len = CSR1212_BE16_TO_CPU(kvi->length);#if 0	/* Apparently there are too many differnt wrong implementations of the	 * CRC algorithm that verifying them is moot. */	if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&	    (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {		ret = CSR1212_EINVAL;		goto fail;	}#endif	switch(kv->key.type) {	case CSR1212_KV_TYPE_DIRECTORY:		for (i = 0; i < kvi_len; i++) {			csr1212_quad_t ki = kvi->data[i];			/* Some devices put null entries in their unit			 * directories.  If we come across such an entry,			 * then skip it. */			if (ki == 0x0)				continue;			ret = csr1212_parse_dir_entry(kv, ki,						      (kv->offset +						       quads_to_bytes(i + 1)));		}		kv->value.directory.len = kvi_len;		break;	case CSR1212_KV_TYPE_LEAF:		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {			kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));			if (!kv->value.leaf.data) {				ret = CSR1212_ENOMEM;				goto fail;			}			kv->value.leaf.len = kvi_len;			memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));		}		break;	}	kv->valid = 1;fail:	return ret;}int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv){	struct csr1212_cache_region *cr, *ncr, *newcr = NULL;	struct csr1212_keyval_img *kvi = NULL;	struct csr1212_csr_rom_cache *cache;	int cache_index;	u_int64_t addr;	u_int32_t *cache_ptr;	u_int16_t kv_len = 0;	if (!csr || !kv || csr->max_rom < 1)		return CSR1212_EINVAL;	/* First find which cache the data should be in (or go in if not read	 * yet). */	for (cache = csr->cache_head; cache; cache = cache->next) {		if (kv->offset >= cache->offset &&		    kv->offset < (cache->offset + cache->size))			break;	}	if (!cache) {		csr1212_quad_t q;		u_int32_t cache_size;		/* Only create a new cache for Extended ROM leaves. */		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)			return CSR1212_EINVAL;		if (csr->ops->bus_read(csr,				       CSR1212_REGISTER_SPACE_BASE + kv->offset,				       sizeof(csr1212_quad_t), &q, csr->private)) {			return CSR1212_EIO;		}		kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16;		cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +			      (csr->max_rom - 1)) & ~(csr->max_rom - 1);		cache = csr1212_rom_cache_malloc(kv->offset, cache_size);		if (!cache)			return CSR1212_ENOMEM;		kv->value.leaf.data = &cache->data[1];		csr->cache_tail->next = cache;		cache->prev = csr->cache_tail;		cache->next = NULL;		csr->cache_tail = cache;		cache->filled_head =			CSR1212_MALLOC(sizeof(*cache->filled_head));		if (!cache->filled_head) {			return CSR1212_ENOMEM;		}		cache->filled_head->offset_start = 0;		cache->filled_head->offset_end = sizeof(csr1212_quad_t);		cache->filled_tail = cache->filled_head;		cache->filled_head->next = NULL;		cache->filled_head->prev = NULL;		cache->data[0] = q;		/* Don't read the entire extended ROM now.  Pieces of it will		 * be read when entries inside it are read. */		return csr1212_parse_keyval(kv, cache);	}	cache_index = kv->offset - cache->offset;	/* Now seach read portions of the cache to see if it is there. */	for (cr = cache->filled_head; cr; cr = cr->next) {		if (cache_index < cr->offset_start) {			newcr = CSR1212_MALLOC(sizeof(*newcr));			if (!newcr)				return CSR1212_ENOMEM;			newcr->offset_start = cache_index & ~(csr->max_rom - 1);			newcr->offset_end = newcr->offset_start;			newcr->next = cr;			newcr->prev = cr->prev;			cr->prev = newcr;			cr = newcr;			break;		} else if ((cache_index >= cr->offset_start) &&			   (cache_index < cr->offset_end)) {			kvi = (struct csr1212_keyval_img*)				(&cache->data[bytes_to_quads(cache_index)]);			kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +						1);			break;		} else if (cache_index == cr->offset_end)			break;	}	if (!cr) {		cr = cache->filled_tail;		newcr = CSR1212_MALLOC(sizeof(*newcr));		if (!newcr)			return CSR1212_ENOMEM;		newcr->offset_start = cache_index & ~(csr->max_rom - 1);		newcr->offset_end = newcr->offset_start;		newcr->prev = cr;		newcr->next = cr->next;		cr->next = newcr;		cr = newcr;		cache->filled_tail = newcr;	}	while(!kvi || cr->offset_end < cache_index + kv_len) {		cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &							~(csr->max_rom - 1))];		addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +			cr->offset_end) & ~(csr->max_rom - 1);		if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,				       csr->private)) {			if (csr->max_rom == 4)				/* We've got problems! */				return CSR1212_EIO;			/* Apperently the max_rom value was a lie, set it to			 * do quadlet reads and try again. */			csr->max_rom = 4;			continue;		}		cr->offset_end += csr->max_rom - (cr->offset_end &						  (csr->max_rom - 1));		if (!kvi && (cr->offset_end > cache_index)) {			kvi = (struct csr1212_keyval_img*)				(&cache->data[bytes_to_quads(cache_index)]);			kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +						1);		}		if ((kv_len + (kv->offset - cache->offset)) > cache->size) {			/* The Leaf or Directory claims its length extends			 * beyond the ConfigROM image region and thus beyond the			 * end of our cache region.  Therefore, we abort now			 * rather than seg faulting later. */			return CSR1212_EIO;		}		ncr = cr->next;		if (ncr && (cr->offset_end >= ncr->offset_start)) {			/* consolidate region entries */			ncr->offset_start = cr->offset_start;			if (cr->prev)				cr->prev->next = cr->next;			ncr->prev = cr->prev;			if (cache->filled_head == cr)				cache->filled_head = ncr;			CSR1212_FREE(cr);			cr = ncr;		}	}	return csr1212_parse_keyval(kv, cache);}int csr1212_parse_csr(struct csr1212_csr *csr){	static const int mr_map[] = { 4, 64, 1024, 0 };	struct csr1212_dentry *dentry;	int ret;	if (!csr || !csr->ops || !csr->ops->bus_read)		return CSR1212_EINVAL;	ret = csr1212_parse_bus_info_block(csr);	if (ret != CSR1212_SUCCESS)		return ret;	if (!csr->ops->get_max_rom)		csr->max_rom = mr_map[0];	/* default value */	else {		int i = csr->ops->get_max_rom(csr->bus_info_data,					      csr->private);		if (i & ~0x3)			return CSR1212_EINVAL;		csr->max_rom = mr_map[i];	}	csr->cache_head->layout_head = csr->root_kv;	csr->cache_head->layout_tail = csr->root_kv;	csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +		csr->bus_info_len;	csr->root_kv->valid = 0;	csr->root_kv->next = csr->root_kv;	csr->root_kv->prev = csr->root_kv;	ret = _csr1212_read_keyval(csr, csr->root_kv);	if (ret != CSR1212_SUCCESS)		return ret;	/* Scan through the Root directory finding all extended ROM regions	 * and make cache regions for them */	for (dentry = csr->root_kv->value.directory.dentries_head;	     dentry; dentry = dentry->next) {		if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&			!dentry->kv->valid) {			ret = _csr1212_read_keyval(csr, dentry->kv);			if (ret != CSR1212_SUCCESS)				return ret;		}	}	return CSR1212_SUCCESS;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -