📄 csr1212.c
字号:
int pixel_size = (hscan * vscan + 3) & ~0x3; if (!pixels || (!palette && palette_depth) || (palette_depth & ~0x3) || (color_space & ~0xf)) return NULL; palette_size = pd[palette_depth] * cs[color_space]; kv = csr1212_new_descriptor_leaf(1, 0, NULL, palette_size + pixel_size + CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD); if (!kv) return NULL; CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version); CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth); CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space); CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language); CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan); CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan); if (palette_size) memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv), palette, palette_size); memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(kv), pixels, pixel_size); return kv;}struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size, u_int64_t address){ struct csr1212_keyval *kv; /* IEEE 1212, par. 7.5.4.3 Modifiable descriptors */ kv = csr1212_new_leaf(CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR, NULL, sizeof(u_int64_t)); if(!kv) return NULL; CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, max_size); CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, address); CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, address); return kv;}static int csr1212_check_keyword(const char *s){ for (; *s; s++) { if (('A' <= *s) && (*s <= 'Z')) continue; if (('0' <= *s) && (*s <= '9')) continue; if (*s == '-') continue; return -1; /* failed */ } /* String conforms to keyword, as specified by IEEE 1212, * par. 7.6.5 */ return CSR1212_SUCCESS;}struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, const char *strv[]){ struct csr1212_keyval *kv; char *buffer; int i, data_len = 0; /* Check all keywords to see if they conform to restrictions: * Only the following characters is allowed ['A'..'Z','0'..'9','-'] * Each word is zero-terminated. * Also calculate the total length of the keywords. */ for (i = 0; i < strc; i++) { if (!strv[i] || csr1212_check_keyword(strv[i])) { return NULL; } data_len += strlen(strv[i]) + 1; /* Add zero-termination char. */ } /* IEEE 1212, par. 7.6.5 Keyword leaves */ kv = csr1212_new_leaf(CSR1212_KV_ID_KEYWORD, NULL, data_len); if (!kv) return NULL; buffer = (char *)kv->value.leaf.data; /* make sure last quadlet is zeroed out */ *((u_int32_t*)&(buffer[(data_len - 1) & ~0x3])) = 0; /* Copy keyword(s) into leaf data buffer */ for (i = 0; i < strc; i++) { int len = strlen(strv[i]) + 1; memcpy(buffer, strv[i], len); buffer += len; } return kv;}/* Destruction Routines */void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, struct csr1212_keyval *kv){ struct csr1212_dentry *dentry; if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY) return; dentry = csr1212_find_keyval(dir, kv); if (!dentry) return; if (dentry->prev) dentry->prev->next = dentry->next; if (dentry->next) dentry->next->prev = dentry->prev; if (dir->value.directory.dentries_head == dentry) dir->value.directory.dentries_head = dentry->next; if (dir->value.directory.dentries_tail == dentry) dir->value.directory.dentries_tail = dentry->prev; CSR1212_FREE(dentry); csr1212_release_keyval(kv);}void csr1212_disassociate_keyval(struct csr1212_keyval *kv){ if (kv->associate) { csr1212_release_keyval(kv->associate); } kv->associate = NULL;}/* This function is used to free the memory taken by a keyval. If the given * keyval is a directory type, then any keyvals contained in that directory * will be destroyed as well if their respective refcnts are 0. By means of * list manipulation, this routine will descend a directory structure in a * non-recursive manner. */void _csr1212_destroy_keyval(struct csr1212_keyval *kv){ struct csr1212_keyval *k, *a; struct csr1212_dentry dentry; struct csr1212_dentry *head, *tail; dentry.kv = kv; dentry.next = NULL; dentry.prev = NULL; head = &dentry; tail = head; while (head) { k = head->kv; while (k) { k->refcnt--; if (k->refcnt > 0) break; a = k->associate; if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) { /* If the current entry is a directory, then move all * the entries to the destruction list. */ if (k->value.directory.dentries_head) { tail->next = k->value.directory.dentries_head; k->value.directory.dentries_head->prev = tail; tail = k->value.directory.dentries_tail; } } free_keyval(k); k = a; } head = head->next; if (head) { if (head->prev && head->prev != &dentry) { CSR1212_FREE(head->prev); } head->prev = NULL; } else if (tail != &dentry) CSR1212_FREE(tail); }}void csr1212_destroy_csr(struct csr1212_csr *csr){ struct csr1212_csr_rom_cache *c, *oc; struct csr1212_cache_region *cr, *ocr; csr1212_release_keyval(csr->root_kv); c = csr->cache_head; while (c) { oc = c; cr = c->filled_head; while (cr) { ocr = cr; cr = cr->next; CSR1212_FREE(ocr); } c = c->next; CSR1212_FREE(oc); } CSR1212_FREE(csr);}/* CSR Image Creation */static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize){ struct csr1212_csr_rom_cache *cache; u_int64_t csr_addr; if (!csr || !csr->ops || !csr->ops->allocate_addr_range || !csr->ops->release_addr || csr->max_rom < 1) return CSR1212_EINVAL; /* ROM size must be a multiple of csr->max_rom */ romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1); csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private); if (csr_addr == CSR1212_INVALID_ADDR_SPACE) { return CSR1212_ENOMEM; } if (csr_addr < CSR1212_REGISTER_SPACE_BASE) { /* Invalid address returned from allocate_addr_range(). */ csr->ops->release_addr(csr_addr, csr->private); return CSR1212_ENOMEM; } cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize); if (!cache) { csr->ops->release_addr(csr_addr, csr->private); return CSR1212_ENOMEM; } cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM); if (!cache->ext_rom) { csr->ops->release_addr(csr_addr, csr->private); CSR1212_FREE(cache); return CSR1212_ENOMEM; } if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) { csr1212_release_keyval(cache->ext_rom); csr->ops->release_addr(csr_addr, csr->private); CSR1212_FREE(cache); return CSR1212_ENOMEM; } cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE; cache->ext_rom->value.leaf.len = -1; cache->ext_rom->value.leaf.data = cache->data; /* Add cache to tail of cache list */ cache->prev = csr->cache_tail; csr->cache_tail->next = cache; csr->cache_tail = cache; return CSR1212_SUCCESS;}static inline void csr1212_remove_cache(struct csr1212_csr *csr, struct csr1212_csr_rom_cache *cache){ if (csr->cache_head == cache) csr->cache_head = cache->next; if (csr->cache_tail == cache) csr->cache_tail = cache->prev; if (cache->prev) cache->prev->next = cache->next; if (cache->next) cache->next->prev = cache->prev; if (cache->ext_rom) { csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom); csr1212_release_keyval(cache->ext_rom); } CSR1212_FREE(cache);}static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, struct csr1212_keyval **layout_tail){ struct csr1212_dentry *dentry; struct csr1212_keyval *dkv; struct csr1212_keyval *last_extkey_spec = NULL; struct csr1212_keyval *last_extkey = NULL; int num_entries = 0; for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) { for (dkv = dentry->kv; dkv; dkv = dkv->associate) { /* Special Case: Extended Key Specifier_ID */ if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { if (last_extkey_spec == NULL) { last_extkey_spec = dkv; } else if (dkv->value.immediate != last_extkey_spec->value.immediate) { last_extkey_spec = dkv; } else { continue; } /* Special Case: Extended Key */ } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) { if (last_extkey == NULL) { last_extkey = dkv; } else if (dkv->value.immediate != last_extkey->value.immediate) { last_extkey = dkv; } else { continue; } } num_entries += 1; switch(dkv->key.type) { default: case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_CSR_OFFSET: break; case CSR1212_KV_TYPE_LEAF: case CSR1212_KV_TYPE_DIRECTORY: /* Remove from list */ if (dkv->prev && (dkv->prev->next == dkv)) dkv->prev->next = dkv->next; if (dkv->next && (dkv->next->prev == dkv)) dkv->next->prev = dkv->prev; //if (dkv == *layout_tail) // *layout_tail = dkv->prev; /* Special case: Extended ROM leafs */ if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { dkv->value.leaf.len = -1; /* Don't add Extended ROM leafs in the layout list, * they are handled differently. */ break; } /* Add to tail of list */ dkv->next = NULL; dkv->prev = *layout_tail; (*layout_tail)->next = dkv; *layout_tail = dkv; break; } } } return num_entries;}size_t csr1212_generate_layout_order(struct csr1212_keyval *kv){ struct csr1212_keyval *ltail = kv; size_t agg_size = 0; while(kv) { switch(kv->key.type) { case CSR1212_KV_TYPE_LEAF: /* Add 1 quadlet for crc/len field */ agg_size += kv->value.leaf.len + 1; break; case CSR1212_KV_TYPE_DIRECTORY: kv->value.directory.len = csr1212_generate_layout_subdir(kv, <ail); /* Add 1 quadlet for crc/len field */ agg_size += kv->value.directory.len + 1; break; } kv = kv->next; } return quads_to_bytes(agg_size);}struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, struct csr1212_keyval *start_kv, int start_pos){ struct csr1212_keyval *kv = start_kv; struct csr1212_keyval *okv = start_kv; int pos = start_pos; int kv_len = 0, okv_len = 0; cache->layout_head = kv; while(kv && pos < cache->size) { /* Special case: Extended ROM leafs */ if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { kv->offset = cache->offset + pos; } switch(kv->key.type) { case CSR1212_KV_TYPE_LEAF: kv_len = kv->value.leaf.len; break; case CSR1212_KV_TYPE_DIRECTORY: kv_len = kv->value.directory.len; break; default: /* Should never get here */ break; } pos += quads_to_bytes(kv_len + 1); if (pos <= cache->size) { okv = kv; okv_len = kv_len; kv = kv->next; } } cache->layout_tail = okv; cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1); return kv;}static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u_int32_t *data_buffer){ struct csr1212_dentry *dentry; struct csr1212_keyval *last_extkey_spec = NULL; struct csr1212_keyval *last_extkey = NULL; int index = 0; for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) { struct csr1212_keyval *a; for (a = dentry->kv; a; a = a->associate) { u_int32_t value = 0; /* Special Case: Extended Key Specifier_ID */ if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { if (last_extkey_spec == NULL) { last_extkey_spec = a; } else if (a->value.immediate != last_extkey_spec->value.immediate) { last_extkey_spec = a; } else { continue; } /* Special Case: Extended Key */ } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) { if (last_extkey == NULL) { last_extkey = a; } else if (a->value.immediate != last_extkey->value.immediate) { last_extkey = a; } else { continue; } } switch(a->key.type) { case CSR1212_KV_TYPE_IMMEDIATE: value = a->value.immediate; break; case CSR1212_KV_TYPE_CSR_OFFSET: value = a->value.csr_offset; break; case CSR1212_KV_TYPE_LEAF: value = a->offset; value -= dir->offset + quads_to_bytes(1+index); value = bytes_to_quads(value); break; case CSR1212_KV_TYPE_DIRECTORY: value = a->offset; value -= dir->offset + quads_to_bytes(1+index); value = bytes_to_quads(value); break; default: /* Should never get here */ break; /* GDB breakpoint */ } value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT; value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) << (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT); data_buffer[index] = CSR1212_CPU_TO_BE32(value); index++; } }}void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache){ struct csr1212_keyval *kv, *nkv; struct csr1212_keyval_img *kvi; for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) { kvi = (struct csr1212_keyval_img *) (cache->data + bytes_to_quads(kv->offset - cache->offset)); switch(kv->key.type) { default: case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_CSR_OFFSET: /* Should never get here */ break; /* GDB breakpoint */ case CSR1212_KV_TYPE_LEAF: /* Don't copy over Extended ROM areas, they are * already filled out! */ if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) memcpy(kvi->data, kv->value.leaf.data, quads_to_bytes(kv->value.leaf.len)); kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len); kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len); break; case CSR1212_KV_TYPE_DIRECTORY: csr1212_generate_tree_subdir(kv, kvi->data); kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len); kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len); break; } nkv = kv->next; if (kv->prev) kv->prev->next = NULL; if (kv->next) kv->next->prev = NULL; kv->prev = NULL; kv->next = NULL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -