/* ========================================================================= * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $ * $Revision: #4 $ * $Date: 2010/11/04 $ * $Change: 1621692 $ * * Synopsys Portability Library Software and documentation * (hereinafter, "Software") is an Unsupported proprietary work of * Synopsys, Inc. unless otherwise expressly agreed to in writing * between Synopsys and you. * * The Software IS NOT an item of Licensed Software or Licensed Product * under any End User Software License Agreement or Agreement for * Licensed Product with Synopsys or any supplement thereto. You are * permitted to use and redistribute this Software in source and binary * forms, with or without modification, provided that redistributions * of source code must retain this notice. You may not view, use, * disclose, copy or distribute this file or any information contained * herein except pursuant to this license grant from Synopsys. If you * do not agree with this notice, including the disclaimer below, then * you are not authorized to use the Software. * * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * ========================================================================= */ #ifdef DWC_CCLIB #include "dwc_cc.h" typedef struct dwc_cc { uint32_t uid; uint8_t chid[16]; uint8_t cdid[16]; uint8_t ck[16]; uint8_t *name; uint8_t length; DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry; } dwc_cc_t; DWC_CIRCLEQ_HEAD(context_list, dwc_cc); /** The main structure for CC management. */ struct dwc_cc_if { dwc_mutex_t *mutex; char *filename; unsigned is_host:1; dwc_notifier_t *notifier; struct context_list list; }; #ifdef DEBUG static inline void dump_bytes(char *name, uint8_t *bytes, int len) { int i; DWC_PRINTF("%s: ", name); for (i=0; ilength = length; cc->name = dwc_alloc(mem_ctx, length); if (!cc->name) { dwc_free(mem_ctx, cc); return NULL; } DWC_MEMCPY(cc->name, name, length); } return cc; } static void free_cc(void *mem_ctx, dwc_cc_t *cc) { if (cc->name) { dwc_free(mem_ctx, cc->name); } dwc_free(mem_ctx, cc); } static uint32_t next_uid(dwc_cc_if_t *cc_if) { uint32_t uid = 0; dwc_cc_t *cc; DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { if (cc->uid > uid) { uid = cc->uid; } } if (uid == 0) { uid = 255; } return uid + 1; } static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid) { dwc_cc_t *cc; DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { if (cc->uid == uid) { return cc; } } return NULL; } static unsigned int cc_data_size(dwc_cc_if_t *cc_if) { unsigned int size = 0; dwc_cc_t *cc; DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { size += (48 + 1); if (cc->name) { size += cc->length; } } return size; } static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid) { uint32_t uid = 0; dwc_cc_t *cc; DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { if (DWC_MEMCMP(cc->chid, chid, 16) == 0) { uid = cc->uid; break; } } return uid; } static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid) { uint32_t uid = 0; dwc_cc_t *cc; DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) { uid = cc->uid; break; } } return uid; } /* Internal cc_add */ static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) { dwc_cc_t *cc; uint32_t uid; if (cc_if->is_host) { uid = cc_match_cdid(cc_if, cdid); } else { uid = cc_match_chid(cc_if, chid); } if (uid) { DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length); cc = cc_find(cc_if, uid); } else { cc = alloc_cc(mem_ctx, name, length); cc->uid = next_uid(cc_if); DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry); } DWC_MEMCPY(&(cc->chid[0]), chid, 16); DWC_MEMCPY(&(cc->cdid[0]), cdid, 16); DWC_MEMCPY(&(cc->ck[0]), ck, 16); DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length); dump_bytes("CHID", cc->chid, 16); dump_bytes("CDID", cc->cdid, 16); dump_bytes("CK", cc->ck, 16); return cc->uid; } /* Internal cc_clear */ static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if) { while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) { dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list); DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry); free_cc(mem_ctx, cc); } } dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx, dwc_notifier_t *notifier, unsigned is_host) { dwc_cc_if_t *cc_if = NULL; /* Allocate a common_cc_if structure */ cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t)); if (!cc_if) return NULL; #if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex); #else cc_if->mutex = dwc_mutex_alloc(mtx_ctx); #endif if (!cc_if->mutex) { dwc_free(mem_ctx, cc_if); return NULL; } DWC_CIRCLEQ_INIT(&cc_if->list); cc_if->is_host = is_host; cc_if->notifier = notifier; return cc_if; } void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if) { #if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) DWC_MUTEX_FREE(cc_if->mutex); #else dwc_mutex_free(mtx_ctx, cc_if->mutex); #endif cc_clear(mem_ctx, cc_if); dwc_free(mem_ctx, cc_if); } static void cc_changed(dwc_cc_if_t *cc_if) { if (cc_if->notifier) { dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if); } } void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if) { DWC_MUTEX_LOCK(cc_if->mutex); cc_clear(mem_ctx, cc_if); DWC_MUTEX_UNLOCK(cc_if->mutex); cc_changed(cc_if); } int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) { uint32_t uid; DWC_MUTEX_LOCK(cc_if->mutex); uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length); DWC_MUTEX_UNLOCK(cc_if->mutex); cc_changed(cc_if); return uid; } void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) { dwc_cc_t* cc; DWC_DEBUGC("Change connection context %d", id); DWC_MUTEX_LOCK(cc_if->mutex); cc = cc_find(cc_if, id); if (!cc) { DWC_ERROR("Uid %d not found in cc list\n", id); DWC_MUTEX_UNLOCK(cc_if->mutex); return; } if (chid) { DWC_MEMCPY(&(cc->chid[0]), chid, 16); } if (cdid) { DWC_MEMCPY(&(cc->cdid[0]), cdid, 16); } if (ck) { DWC_MEMCPY(&(cc->ck[0]), ck, 16); } if (name) { if (cc->name) { dwc_free(mem_ctx, cc->name); } cc->name = dwc_alloc(mem_ctx, length); if (!cc->name) { DWC_ERROR("Out of memory in dwc_cc_change()\n"); DWC_MUTEX_UNLOCK(cc_if->mutex); return; } cc->length = length; DWC_MEMCPY(cc->name, name, length); } DWC_MUTEX_UNLOCK(cc_if->mutex); cc_changed(cc_if); DWC_DEBUGC("Changed connection context id=%d\n", id); dump_bytes("New CHID", cc->chid, 16); dump_bytes("New CDID", cc->cdid, 16); dump_bytes("New CK", cc->ck, 16); } void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id) { dwc_cc_t *cc; DWC_DEBUGC("Removing connection context %d", id); DWC_MUTEX_LOCK(cc_if->mutex); cc = cc_find(cc_if, id); if (!cc) { DWC_ERROR("Uid %d not found in cc list\n", id); DWC_MUTEX_UNLOCK(cc_if->mutex); return; } DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry); DWC_MUTEX_UNLOCK(cc_if->mutex); free_cc(mem_ctx, cc); cc_changed(cc_if); } uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length) { uint8_t *buf, *x; uint8_t zero = 0; dwc_cc_t *cc; DWC_MUTEX_LOCK(cc_if->mutex); *length = cc_data_size(cc_if); if (!(*length)) { DWC_MUTEX_UNLOCK(cc_if->mutex); return NULL; } DWC_DEBUGC("Creating data for saving (length=%d)", *length); buf = dwc_alloc(mem_ctx, *length); if (!buf) { *length = 0; DWC_MUTEX_UNLOCK(cc_if->mutex); return NULL; } x = buf; DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { DWC_MEMCPY(x, cc->chid, 16); x += 16; DWC_MEMCPY(x, cc->cdid, 16); x += 16; DWC_MEMCPY(x, cc->ck, 16); x += 16; if (cc->name) { DWC_MEMCPY(x, &cc->length, 1); x += 1; DWC_MEMCPY(x, cc->name, cc->length); x += cc->length; } else { DWC_MEMCPY(x, &zero, 1); x += 1; } } DWC_MUTEX_UNLOCK(cc_if->mutex); return buf; } void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length) { uint8_t name_length; uint8_t *name; uint8_t *chid; uint8_t *cdid; uint8_t *ck; uint32_t i = 0; DWC_MUTEX_LOCK(cc_if->mutex); cc_clear(mem_ctx, cc_if); while (i < length) { chid = &data[i]; i += 16; cdid = &data[i]; i += 16; ck = &data[i]; i += 16; name_length = data[i]; i ++; if (name_length) { name = &data[i]; i += name_length; } else { name = NULL; } /* check to see if we haven't overflown the buffer */ if (i > length) { DWC_ERROR("Data format error while attempting to load CCs " "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length); break; } cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length); } DWC_MUTEX_UNLOCK(cc_if->mutex); cc_changed(cc_if); } uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid) { uint32_t uid = 0; DWC_MUTEX_LOCK(cc_if->mutex); uid = cc_match_chid(cc_if, chid); DWC_MUTEX_UNLOCK(cc_if->mutex); return uid; } uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid) { uint32_t uid = 0; DWC_MUTEX_LOCK(cc_if->mutex); uid = cc_match_cdid(cc_if, cdid); DWC_MUTEX_UNLOCK(cc_if->mutex); return uid; } uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id) { uint8_t *ck = NULL; dwc_cc_t *cc; DWC_MUTEX_LOCK(cc_if->mutex); cc = cc_find(cc_if, id); if (cc) { ck = cc->ck; } DWC_MUTEX_UNLOCK(cc_if->mutex); return ck; } uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id) { uint8_t *retval = NULL; dwc_cc_t *cc; DWC_MUTEX_LOCK(cc_if->mutex); cc = cc_find(cc_if, id); if (cc) { retval = cc->chid; } DWC_MUTEX_UNLOCK(cc_if->mutex); return retval; } uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id) { uint8_t *retval = NULL; dwc_cc_t *cc; DWC_MUTEX_LOCK(cc_if->mutex); cc = cc_find(cc_if, id); if (cc) { retval = cc->cdid; } DWC_MUTEX_UNLOCK(cc_if->mutex); return retval; } uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length) { uint8_t *retval = NULL; dwc_cc_t *cc; DWC_MUTEX_LOCK(cc_if->mutex); *length = 0; cc = cc_find(cc_if, id); if (cc) { *length = cc->length; retval = cc->name; } DWC_MUTEX_UNLOCK(cc_if->mutex); return retval; } #endif /* DWC_CCLIB */