#include #include #include #include #ifdef GSC3280_CCLIB # include "gsc3280_cc.h" #endif #ifdef GSC3280_CRYPTOLIB # include "gsc3280_modpow.h" # include "gsc3280_dh.h" # include "gsc3280_crypto.h" #endif #ifdef GSC3280_NOTIFYLIB # include "gsc3280_notifier.h" #endif /* OS-Level Implementations */ /* This is the Linux kernel implementation of the GSC3280 platform library. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) # include #else # include #endif #include #include #include #include #include "gsc3280_os.h" #include "gsc3280_list.h" /* MISC */ void *GSC3280_MEMSET(void *dest, uint8_t byte, uint32_t size) { return memset(dest, byte, size); } void *GSC3280_MEMCPY(void *dest, void const *src, uint32_t size) { return memcpy(dest, src, size); } void *GSC3280_MEMMOVE(void *dest, void *src, uint32_t size) { return memmove(dest, src, size); } int GSC3280_MEMCMP(void *m1, void *m2, uint32_t size) { return memcmp(m1, m2, size); } int GSC3280_STRNCMP(void *s1, void *s2, uint32_t size) { return strncmp(s1, s2, size); } int GSC3280_STRCMP(void *s1, void *s2) { return strcmp(s1, s2); } int GSC3280_STRLEN(char const *str) { return strlen(str); } char *GSC3280_STRCPY(char *to, char const *from) { return strcpy(to, from); } char *GSC3280_STRDUP(char const *str) { int len = GSC3280_STRLEN(str) + 1; char *new = GSC3280_ALLOC_ATOMIC(len); if (!new) { return NULL; } GSC3280_MEMCPY(new, str, len); return new; } int GSC3280_ATOI(const char *str, int32_t *value) { char *end = NULL; *value = simple_strtol(str, &end, 0); if (*end == '\0') { return 0; } return -1; } int GSC3280_ATOUI(const char *str, uint32_t *value) { char *end = NULL; *value = simple_strtoul(str, &end, 0); if (*end == '\0') { return 0; } return -1; } #ifdef GSC3280_UTFLIB /* From usbstring.c */ int GSC3280_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len) { int count = 0; u8 c; u16 uchar; /* this insists on correct encodings, though not minimal ones. * BUT it currently rejects legit 4-byte UTF-8 code points, * which need surrogate pairs. (Unicode 3.1 can use them.) */ while (len != 0 && (c = (u8) *s++) != 0) { if (unlikely(c & 0x80)) { // 2-byte sequence: // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx if ((c & 0xe0) == 0xc0) { uchar = (c & 0x1f) << 6; c = (u8) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c; // 3-byte sequence (most CJKV characters): // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx } else if ((c & 0xf0) == 0xe0) { uchar = (c & 0x0f) << 12; c = (u8) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c << 6; c = (u8) *s++; if ((c & 0xc0) != 0xc0) goto fail; c &= 0x3f; uchar |= c; /* no bogus surrogates */ if (0xd800 <= uchar && uchar <= 0xdfff) goto fail; // 4-byte sequence (surrogate pairs, currently rare): // 11101110wwwwzzzzyy + 110111yyyyxxxxxx // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx // (uuuuu = wwww + 1) // FIXME accept the surrogate code points (only) } else goto fail; } else uchar = c; put_unaligned (cpu_to_le16 (uchar), cp++); count++; len--; } return count; fail: return -1; } #endif /* GSC3280_UTFLIB */ /* gsc3280_debug.h */ gsc3280_bool_t GSC3280_IN_IRQ(void) { return in_irq(); } gsc3280_bool_t GSC3280_IN_BH(void) { return in_softirq(); } void GSC3280_VPRINTF(char *format, va_list args) { vprintk(format, args); } int GSC3280_VSNPRINTF(char *str, int size, char *format, va_list args) { return vsnprintf(str, size, format, args); } void GSC3280_PRINTF(char *format, ...) { va_list args; va_start(args, format); GSC3280_VPRINTF(format, args); va_end(args); } int GSC3280_SPRINTF(char *buffer, char *format, ...) { int retval; va_list args; va_start(args, format); retval = vsprintf(buffer, format, args); va_end(args); return retval; } int GSC3280_SNPRINTF(char *buffer, int size, char *format, ...) { int retval; va_list args; va_start(args, format); retval = vsnprintf(buffer, size, format, args); va_end(args); return retval; } void __GSC3280_WARN(char *format, ...) { va_list args; va_start(args, format); GSC3280_PRINTF(KERN_WARNING); GSC3280_VPRINTF(format, args); va_end(args); } void __GSC3280_ERROR(char *format, ...) { va_list args; va_start(args, format); GSC3280_PRINTF(KERN_ERR); GSC3280_VPRINTF(format, args); va_end(args); } void GSC3280_EXCEPTION(char *format, ...) { va_list args; va_start(args, format); GSC3280_PRINTF(KERN_ERR); GSC3280_VPRINTF(format, args); va_end(args); BUG_ON(1); } #ifdef DEBUG void __GSC3280_DEBUG(char *format, ...) { va_list args; va_start(args, format); GSC3280_PRINTF(KERN_DEBUG); GSC3280_VPRINTF(format, args); va_end(args); } #endif /* gsc3280_mem.h */ #if 0 gsc3280_pool_t *GSC3280_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t alloc) { struct dma_pool *pool = dma_pool_create("Pool", NULL, size, align, alloc); return (gsc3280_pool_t *)pool; } void GSC3280_DMA_POOL_DESTROY(gsc3280_pool_t *pool) { dma_pool_destroy((struct dma_pool *)pool); } void *GSC3280_DMA_POOL_ALLOC(gsc3280_pool_t *pool, uint64_t *dma_addr) { return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr); } void *GSC3280_DMA_POOL_ZALLOC(gsc3280_pool_t *pool, uint64_t *dma_addr) { void *vaddr = GSC3280_DMA_POOL_ALLOC(pool, dma_addr); memset(..); } void GSC3280_DMA_POOL_FREE(gsc3280_pool_t *pool, void *vaddr, void *daddr) { dma_pool_free(pool, vaddr, daddr); } #endif void *__GSC3280_DMA_ALLOC(void *dma_ctx, uint32_t size, gsc3280_dma_t *dma_addr) { #ifdef xxCOSIM /* Only works for 32-bit cosim */ void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL); #else void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32); #endif if (!buf) { return NULL; } // printk("alloc dma_addr is %x\n",*dma_addr); *dma_addr &=0x7FFFFFFF; // memset(buf, 0, (size_t)size); return buf; } void *__GSC3280_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, gsc3280_dma_t *dma_addr) { void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC); if (!buf) { return NULL; } memset(buf, 0, (size_t)size); return buf; } void __GSC3280_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, gsc3280_dma_t dma_addr) { dma_free_coherent(dma_ctx, size, virt_addr, dma_addr); } void *__GSC3280_ALLOC(void *mem_ctx, uint32_t size) { return kzalloc(size, GFP_KERNEL); } void *__GSC3280_ALLOC_ATOMIC(void *mem_ctx, uint32_t size) { return kzalloc(size, GFP_ATOMIC); } void __GSC3280_FREE(void *mem_ctx, void *addr) { kfree(addr); } #ifdef GSC3280_CRYPTOLIB /* gsc3280_crypto.h */ void GSC3280_RANDOM_BYTES(uint8_t *buffer, uint32_t length) { get_random_bytes(buffer, length); } int GSC3280_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out) { struct crypto_blkcipher *tfm; struct blkcipher_desc desc; struct scatterlist sgd; struct scatterlist sgs; tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); if (tfm == NULL) { printk("failed to load transform for aes CBC\n"); return -1; } crypto_blkcipher_setkey(tfm, key, keylen); crypto_blkcipher_set_iv(tfm, iv, 16); sg_init_one(&sgd, out, messagelen); sg_init_one(&sgs, message, messagelen); desc.tfm = tfm; desc.flags = 0; if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) { crypto_free_blkcipher(tfm); GSC3280_ERROR("AES CBC encryption failed"); return -1; } crypto_free_blkcipher(tfm); return 0; } int GSC3280_SHA256(uint8_t *message, uint32_t len, uint8_t *out) { struct crypto_hash *tfm; struct hash_desc desc; struct scatterlist sg; tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { GSC3280_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm)); return 0; } desc.tfm = tfm; desc.flags = 0; sg_init_one(&sg, message, len); crypto_hash_digest(&desc, &sg, len, out); crypto_free_hash(tfm); return 1; } int GSC3280_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out) { struct crypto_hash *tfm; struct hash_desc desc; struct scatterlist sg; tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { GSC3280_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm)); return 0; } desc.tfm = tfm; desc.flags = 0; sg_init_one(&sg, message, messagelen); crypto_hash_setkey(tfm, key, keylen); crypto_hash_digest(&desc, &sg, messagelen, out); crypto_free_hash(tfm); return 1; } #endif /* GSC3280_CRYPTOLIB */ /* Byte Ordering Conversions */ uint32_t GSC3280_CPU_TO_LE32(uint32_t *p) { #ifdef __LITTLE_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); #endif } uint32_t GSC3280_CPU_TO_BE32(uint32_t *p) { #ifdef __BIG_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); #endif } uint32_t GSC3280_LE32_TO_CPU(uint32_t *p) { #ifdef __LITTLE_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); #endif } uint32_t GSC3280_BE32_TO_CPU(uint32_t *p) { #ifdef __BIG_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); #endif } uint16_t GSC3280_CPU_TO_LE16(uint16_t *p) { #ifdef __LITTLE_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[1] | (u_p[0] << 8)); #endif } uint16_t GSC3280_CPU_TO_BE16(uint16_t *p) { #ifdef __BIG_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[1] | (u_p[0] << 8)); #endif } uint16_t GSC3280_LE16_TO_CPU(uint16_t *p) { #ifdef __LITTLE_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[1] | (u_p[0] << 8)); #endif } uint16_t GSC3280_BE16_TO_CPU(uint16_t *p) { #ifdef __BIG_ENDIAN return *p; #else uint8_t *u_p = (uint8_t *)p; return (u_p[1] | (u_p[0] << 8)); #endif } /* Registers */ uint32_t GSC3280_READ_REG32(uint32_t volatile *reg) { return readl(reg); } #if 0 uint64_t GSC3280_READ_REG64(uint64_t volatile *reg) { } #endif void GSC3280_WRITE_REG32(uint32_t volatile *reg, uint32_t value) { writel(value, reg); } #if 0 void GSC3280_WRITE_REG64(uint64_t volatile *reg, uint64_t value) { } #endif void GSC3280_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask) { writel((readl(reg) & ~clear_mask) | set_mask, reg); } #if 0 void GSC3280_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask) { } #endif /* Locking */ gsc3280_spinlock_t *GSC3280_SPINLOCK_ALLOC(void) { spinlock_t *sl = (spinlock_t *)1; #if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) sl = GSC3280_ALLOC(sizeof(*sl)); if (!sl) { GSC3280_ERROR("Cannot allocate memory for spinlock\n"); return NULL; } spin_lock_init(sl); #endif return (gsc3280_spinlock_t *)sl; } void GSC3280_SPINLOCK_FREE(gsc3280_spinlock_t *lock) { #if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) GSC3280_FREE(lock); #endif } void GSC3280_SPINLOCK(gsc3280_spinlock_t *lock) { #if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) spin_lock((spinlock_t *)lock); #endif } void GSC3280_SPINUNLOCK(gsc3280_spinlock_t *lock) { #if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) spin_unlock((spinlock_t *)lock); #endif } void GSC3280_SPINLOCK_IRQSAVE(gsc3280_spinlock_t *lock, gsc3280_irqflags_t *flags) { gsc3280_irqflags_t f; #if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) spin_lock_irqsave((spinlock_t *)lock, f); #else local_irq_save(f); #endif *flags = f; } void GSC3280_SPINUNLOCK_IRQRESTORE(gsc3280_spinlock_t *lock, gsc3280_irqflags_t flags) { #if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) spin_unlock_irqrestore((spinlock_t *)lock, flags); #else local_irq_restore(flags); #endif } gsc3280_mutex_t *GSC3280_MUTEX_ALLOC(void) { struct mutex *m; gsc3280_mutex_t *mutex = (gsc3280_mutex_t *)GSC3280_ALLOC(sizeof(struct mutex)); if (!mutex) { GSC3280_ERROR("Cannot allocate memory for mutex\n"); return NULL; } m = (struct mutex *)mutex; mutex_init(m); return mutex; } #if (defined(GSC3280_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) #else void GSC3280_MUTEX_FREE(gsc3280_mutex_t *mutex) { mutex_destroy((struct mutex *)mutex); GSC3280_FREE(mutex); } #endif void GSC3280_MUTEX_LOCK(gsc3280_mutex_t *mutex) { struct mutex *m = (struct mutex *)mutex; mutex_lock(m); } int GSC3280_MUTEX_TRYLOCK(gsc3280_mutex_t *mutex) { struct mutex *m = (struct mutex *)mutex; return mutex_trylock(m); } void GSC3280_MUTEX_UNLOCK(gsc3280_mutex_t *mutex) { struct mutex *m = (struct mutex *)mutex; mutex_unlock(m); } /* Timing */ void GSC3280_UDELAY(uint32_t usecs) { udelay(usecs); } void GSC3280_MDELAY(uint32_t msecs) { mdelay(msecs); } void GSC3280_MSLEEP(uint32_t msecs) { msleep(msecs); } uint32_t GSC3280_TIME(void) { return jiffies_to_msecs(jiffies); } /* Timers */ struct gsc3280_timer { struct timer_list *t; char *name; gsc3280_timer_callback_t cb; void *data; uint8_t scheduled; gsc3280_spinlock_t *lock; }; static void timer_callback(unsigned long data) { gsc3280_timer_t *timer = (gsc3280_timer_t *)data; gsc3280_irqflags_t flags; GSC3280_SPINLOCK_IRQSAVE(timer->lock, &flags); timer->scheduled = 0; GSC3280_SPINUNLOCK_IRQRESTORE(timer->lock, flags); GSC3280_DEBUG("Timer %s callback", timer->name); timer->cb(timer->data); } gsc3280_timer_t *GSC3280_TIMER_ALLOC(char *name, gsc3280_timer_callback_t cb, void *data) { gsc3280_timer_t *t = GSC3280_ALLOC(sizeof(*t)); if (!t) { GSC3280_ERROR("Cannot allocate memory for timer"); return NULL; } t->t = GSC3280_ALLOC(sizeof(*t->t)); if (!t->t) { GSC3280_ERROR("Cannot allocate memory for timer->t"); goto no_timer; } t->name = GSC3280_STRDUP(name); if (!t->name) { GSC3280_ERROR("Cannot allocate memory for timer->name"); goto no_name; } t->lock = GSC3280_SPINLOCK_ALLOC(); if (!t->lock) { GSC3280_ERROR("Cannot allocate memory for lock"); goto no_lock; } t->scheduled = 0; t->t->base = &boot_tvec_bases; t->t->expires = jiffies; setup_timer(t->t, timer_callback, (unsigned long)t); t->cb = cb; t->data = data; return t; no_lock: GSC3280_FREE(t->name); no_name: GSC3280_FREE(t->t); no_timer: GSC3280_FREE(t); return NULL; } void GSC3280_TIMER_FREE(gsc3280_timer_t *timer) { gsc3280_irqflags_t flags; GSC3280_SPINLOCK_IRQSAVE(timer->lock, &flags); if (timer->scheduled) { del_timer(timer->t); timer->scheduled = 0; } GSC3280_SPINUNLOCK_IRQRESTORE(timer->lock, flags); GSC3280_SPINLOCK_FREE(timer->lock); GSC3280_FREE(timer->t); GSC3280_FREE(timer->name); GSC3280_FREE(timer); } void GSC3280_TIMER_SCHEDULE(gsc3280_timer_t *timer, uint32_t time) { gsc3280_irqflags_t flags; GSC3280_SPINLOCK_IRQSAVE(timer->lock, &flags); if (!timer->scheduled) { timer->scheduled = 1; // GSC3280_DEBUG("Scheduling timer %s to expire in +%d msec", timer->name, time); timer->t->expires = jiffies + msecs_to_jiffies(time); add_timer(timer->t); } else { // GSC3280_DEBUG("Modifying timer %s to expire in +%d msec", timer->name, time); mod_timer(timer->t, jiffies + msecs_to_jiffies(time)); } GSC3280_SPINUNLOCK_IRQRESTORE(timer->lock, flags); } void GSC3280_TIMER_CANCEL(gsc3280_timer_t *timer) { del_timer(timer->t); } /* Wait Queues */ struct gsc3280_waitq { wait_queue_head_t queue; int abort; }; gsc3280_waitq_t *GSC3280_WAITQ_ALLOC(void) { gsc3280_waitq_t *wq = GSC3280_ALLOC(sizeof(*wq)); if (!wq) { GSC3280_ERROR("Cannot allocate memory for waitqueue\n"); return NULL; } init_waitqueue_head(&wq->queue); wq->abort = 0; return wq; } void GSC3280_WAITQ_FREE(gsc3280_waitq_t *wq) { GSC3280_FREE(wq); } int32_t GSC3280_WAITQ_WAIT(gsc3280_waitq_t *wq, gsc3280_waitq_condition_t cond, void *data) { int result = wait_event_interruptible(wq->queue, cond(data) || wq->abort); if (result == -ERESTARTSYS) { wq->abort = 0; return -GSC3280_E_RESTART; } if (wq->abort == 1) { wq->abort = 0; return -GSC3280_E_ABORT; } wq->abort = 0; if (result == 0) { return 0; } return -GSC3280_E_UNKNOWN; } int32_t GSC3280_WAITQ_WAIT_TIMEOUT(gsc3280_waitq_t *wq, gsc3280_waitq_condition_t cond, void *data, int32_t msecs) { int32_t tmsecs; int result = wait_event_interruptible_timeout(wq->queue, cond(data) || wq->abort, msecs_to_jiffies(msecs)); if (result == -ERESTARTSYS) { wq->abort = 0; return -GSC3280_E_RESTART; } if (wq->abort == 1) { wq->abort = 0; return -GSC3280_E_ABORT; } wq->abort = 0; if (result > 0) { tmsecs = jiffies_to_msecs(result); if (!tmsecs) { return 1; } return tmsecs; } if (result == 0) { return -GSC3280_E_TIMEOUT; } return -GSC3280_E_UNKNOWN; } void GSC3280_WAITQ_TRIGGER(gsc3280_waitq_t *wq) { wq->abort = 0; wake_up_interruptible(&wq->queue); } void GSC3280_WAITQ_ABORT(gsc3280_waitq_t *wq) { wq->abort = 1; wake_up_interruptible(&wq->queue); } /* Threading */ gsc3280_thread_t *GSC3280_THREAD_RUN(gsc3280_thread_function_t func, char *name, void *data) { struct task_struct *thread = kthread_run(func, data, name); if (thread == ERR_PTR(-ENOMEM)) { return NULL; } return (gsc3280_thread_t *)thread; } int GSC3280_THREAD_STOP(gsc3280_thread_t *thread) { return kthread_stop((struct task_struct *)thread); } gsc3280_bool_t GSC3280_THREAD_SHOULD_STOP(void) { return kthread_should_stop(); } /* tasklets - run in interrupt context (cannot sleep) - each tasklet runs on a single CPU - different tasklets can be running simultaneously on different CPUs */ struct gsc3280_tasklet { struct tasklet_struct t; gsc3280_tasklet_callback_t cb; void *data; }; static void tasklet_callback(unsigned long data) { gsc3280_tasklet_t *t = (gsc3280_tasklet_t *)data; t->cb(t->data); } gsc3280_tasklet_t *GSC3280_TASK_ALLOC(char *name, gsc3280_tasklet_callback_t cb, void *data) { gsc3280_tasklet_t *t = GSC3280_ALLOC(sizeof(*t)); if (t) { t->cb = cb; t->data = data; tasklet_init(&t->t, tasklet_callback, (unsigned long)t); } else { GSC3280_ERROR("Cannot allocate memory for tasklet\n"); } return t; } void GSC3280_TASK_FREE(gsc3280_tasklet_t *task) { GSC3280_FREE(task); } void GSC3280_TASK_SCHEDULE(gsc3280_tasklet_t *task) { tasklet_schedule(&task->t); } /* workqueues - run in process context (can sleep) */ typedef struct work_container { gsc3280_work_callback_t cb; void *data; gsc3280_workq_t *wq; char *name; #ifdef DEBUG GSC3280_CIRCLEQ_ENTRY(work_container) entry; #endif struct delayed_work work; } work_container_t; #ifdef DEBUG GSC3280_CIRCLEQ_HEAD(work_container_queue, work_container); #endif struct gsc3280_workq { struct workqueue_struct *wq; gsc3280_spinlock_t *lock; gsc3280_waitq_t *waitq; int pending; #ifdef DEBUG struct work_container_queue entries; #endif }; static void do_work(struct work_struct *work) { gsc3280_irqflags_t flags; struct delayed_work *dw = container_of(work, struct delayed_work, work); work_container_t *container = container_of(dw, struct work_container, work); gsc3280_workq_t *wq = container->wq; container->cb(container->data); #ifdef DEBUG GSC3280_CIRCLEQ_REMOVE(&wq->entries, container, entry); #endif GSC3280_DEBUG("Work done: %s, container=%p", container->name, container); if (container->name) { GSC3280_FREE(container->name); } GSC3280_FREE(container); GSC3280_SPINLOCK_IRQSAVE(wq->lock, &flags); wq->pending--; GSC3280_SPINUNLOCK_IRQRESTORE(wq->lock, flags); GSC3280_WAITQ_TRIGGER(wq->waitq); } static int work_done(void *data) { gsc3280_workq_t *workq = (gsc3280_workq_t *)data; return workq->pending == 0; } int GSC3280_WORKQ_WAIT_WORK_DONE(gsc3280_workq_t *workq, int timeout) { return GSC3280_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout); } gsc3280_workq_t *GSC3280_WORKQ_ALLOC(char *name) { gsc3280_workq_t *wq = GSC3280_ALLOC(sizeof(*wq)); if (!wq) { return NULL; } wq->wq = create_singlethread_workqueue(name); if (!wq->wq) { goto no_wq; } wq->pending = 0; wq->lock = GSC3280_SPINLOCK_ALLOC(); if (!wq->lock) { goto no_lock; } wq->waitq = GSC3280_WAITQ_ALLOC(); if (!wq->waitq) { goto no_waitq; } #ifdef DEBUG GSC3280_CIRCLEQ_INIT(&wq->entries); #endif return wq; no_waitq: GSC3280_SPINLOCK_FREE(wq->lock); no_lock: destroy_workqueue(wq->wq); no_wq: GSC3280_FREE(wq); return NULL; } void GSC3280_WORKQ_FREE(gsc3280_workq_t *wq) { #ifdef DEBUG if (wq->pending != 0) { struct work_container *wc; GSC3280_ERROR("Destroying work queue with pending work"); GSC3280_CIRCLEQ_FOREACH(wc, &wq->entries, entry) { GSC3280_ERROR("Work %s still pending", wc->name); } } #endif destroy_workqueue(wq->wq); GSC3280_SPINLOCK_FREE(wq->lock); GSC3280_WAITQ_FREE(wq->waitq); GSC3280_FREE(wq); } void GSC3280_WORKQ_SCHEDULE(gsc3280_workq_t *wq, gsc3280_work_callback_t cb, void *data, char *format, ...) { gsc3280_irqflags_t flags; work_container_t *container; static char name[128]; va_list args; va_start(args, format); GSC3280_VSNPRINTF(name, 128, format, args); va_end(args); GSC3280_SPINLOCK_IRQSAVE(wq->lock, &flags); wq->pending++; GSC3280_SPINUNLOCK_IRQRESTORE(wq->lock, flags); GSC3280_WAITQ_TRIGGER(wq->waitq); container = GSC3280_ALLOC_ATOMIC(sizeof(*container)); if (!container) { GSC3280_ERROR("Cannot allocate memory for container\n"); return; } container->name = GSC3280_STRDUP(name); if (!container->name) { GSC3280_ERROR("Cannot allocate memory for container->name\n"); GSC3280_FREE(container); return; } container->cb = cb; container->data = data; container->wq = wq; GSC3280_DEBUG("Queueing work: %s, container=%p", container->name, container); INIT_WORK(&container->work.work, do_work); #ifdef DEBUG GSC3280_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); #endif queue_work(wq->wq, &container->work.work); } void GSC3280_WORKQ_SCHEDULE_DELAYED(gsc3280_workq_t *wq, gsc3280_work_callback_t cb, void *data, uint32_t time, char *format, ...) { gsc3280_irqflags_t flags; work_container_t *container; static char name[128]; va_list args; va_start(args, format); GSC3280_VSNPRINTF(name, 128, format, args); va_end(args); GSC3280_SPINLOCK_IRQSAVE(wq->lock, &flags); wq->pending++; GSC3280_SPINUNLOCK_IRQRESTORE(wq->lock, flags); GSC3280_WAITQ_TRIGGER(wq->waitq); container = GSC3280_ALLOC_ATOMIC(sizeof(*container)); if (!container) { GSC3280_ERROR("Cannot allocate memory for container\n"); return; } container->name = GSC3280_STRDUP(name); if (!container->name) { GSC3280_ERROR("Cannot allocate memory for container->name\n"); GSC3280_FREE(container); return; } container->cb = cb; container->data = data; container->wq = wq; GSC3280_DEBUG("Queueing work: %s, container=%p", container->name, container); INIT_DELAYED_WORK(&container->work, do_work); #ifdef DEBUG GSC3280_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); #endif queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time)); } int GSC3280_WORKQ_PENDING(gsc3280_workq_t *wq) { return wq->pending; } #ifdef GSC3280_LIBMODULE #ifdef GSC3280_CCLIB /* CC */ EXPORT_SYMBOL(gsc3280_cc_if_alloc); EXPORT_SYMBOL(gsc3280_cc_if_free); EXPORT_SYMBOL(gsc3280_cc_clear); EXPORT_SYMBOL(gsc3280_cc_add); EXPORT_SYMBOL(gsc3280_cc_remove); EXPORT_SYMBOL(gsc3280_cc_change); EXPORT_SYMBOL(gsc3280_cc_data_for_save); EXPORT_SYMBOL(gsc3280_cc_restore_from_data); EXPORT_SYMBOL(gsc3280_cc_match_chid); EXPORT_SYMBOL(gsc3280_cc_match_cdid); EXPORT_SYMBOL(gsc3280_cc_ck); EXPORT_SYMBOL(gsc3280_cc_chid); EXPORT_SYMBOL(gsc3280_cc_cdid); EXPORT_SYMBOL(gsc3280_cc_name); #endif /* GSC3280_CCLIB */ #ifdef GSC3280_CRYPTOLIB # ifndef CONFIG_MACH_IPMATE /* Modpow */ EXPORT_SYMBOL(gsc3280_modpow); /* DH */ EXPORT_SYMBOL(gsc3280_dh_modpow); EXPORT_SYMBOL(gsc3280_dh_derive_keys); EXPORT_SYMBOL(gsc3280_dh_pk); # endif /* CONFIG_MACH_IPMATE */ /* Crypto */ EXPORT_SYMBOL(gsc3280_wusb_aes_encrypt); EXPORT_SYMBOL(gsc3280_wusb_cmf); EXPORT_SYMBOL(gsc3280_wusb_prf); EXPORT_SYMBOL(gsc3280_wusb_fill_ccm_nonce); EXPORT_SYMBOL(gsc3280_wusb_gen_nonce); EXPORT_SYMBOL(gsc3280_wusb_gen_key); EXPORT_SYMBOL(gsc3280_wusb_gen_mic); #endif /* GSC3280_CRYPTOLIB */ /* Notification */ #ifdef GSC3280_NOTIFYLIB EXPORT_SYMBOL(gsc3280_alloc_notification_manager); EXPORT_SYMBOL(gsc3280_free_notification_manager); EXPORT_SYMBOL(gsc3280_register_notifier); EXPORT_SYMBOL(gsc3280_unregister_notifier); EXPORT_SYMBOL(gsc3280_add_observer); EXPORT_SYMBOL(gsc3280_remove_observer); EXPORT_SYMBOL(gsc3280_notify); #endif /* Memory Debugging Routines */ #ifdef GSC3280_DEBUG_MEMORY EXPORT_SYMBOL(gsc3280_alloc_debug); EXPORT_SYMBOL(gsc3280_alloc_atomic_debug); EXPORT_SYMBOL(gsc3280_free_debug); EXPORT_SYMBOL(gsc3280_dma_alloc_debug); EXPORT_SYMBOL(gsc3280_dma_free_debug); #endif EXPORT_SYMBOL(GSC3280_MEMSET); EXPORT_SYMBOL(GSC3280_MEMCPY); EXPORT_SYMBOL(GSC3280_MEMMOVE); EXPORT_SYMBOL(GSC3280_MEMCMP); EXPORT_SYMBOL(GSC3280_STRNCMP); EXPORT_SYMBOL(GSC3280_STRCMP); EXPORT_SYMBOL(GSC3280_STRLEN); EXPORT_SYMBOL(GSC3280_STRCPY); EXPORT_SYMBOL(GSC3280_STRDUP); EXPORT_SYMBOL(GSC3280_ATOI); EXPORT_SYMBOL(GSC3280_ATOUI); #ifdef GSC3280_UTFLIB EXPORT_SYMBOL(GSC3280_UTF8_TO_UTF16LE); #endif /* GSC3280_UTFLIB */ EXPORT_SYMBOL(GSC3280_IN_IRQ); EXPORT_SYMBOL(GSC3280_IN_BH); EXPORT_SYMBOL(GSC3280_VPRINTF); EXPORT_SYMBOL(GSC3280_VSNPRINTF); EXPORT_SYMBOL(GSC3280_PRINTF); EXPORT_SYMBOL(GSC3280_SPRINTF); EXPORT_SYMBOL(GSC3280_SNPRINTF); EXPORT_SYMBOL(__GSC3280_WARN); EXPORT_SYMBOL(__GSC3280_ERROR); EXPORT_SYMBOL(GSC3280_EXCEPTION); #ifdef DEBUG EXPORT_SYMBOL(__GSC3280_DEBUG); #endif EXPORT_SYMBOL(__GSC3280_DMA_ALLOC); EXPORT_SYMBOL(__GSC3280_DMA_ALLOC_ATOMIC); EXPORT_SYMBOL(__GSC3280_DMA_FREE); EXPORT_SYMBOL(__GSC3280_ALLOC); EXPORT_SYMBOL(__GSC3280_ALLOC_ATOMIC); EXPORT_SYMBOL(__GSC3280_FREE); #ifdef GSC3280_CRYPTOLIB EXPORT_SYMBOL(GSC3280_RANDOM_BYTES); EXPORT_SYMBOL(GSC3280_AES_CBC); EXPORT_SYMBOL(GSC3280_SHA256); EXPORT_SYMBOL(GSC3280_HMAC_SHA256); #endif EXPORT_SYMBOL(GSC3280_CPU_TO_LE32); EXPORT_SYMBOL(GSC3280_CPU_TO_BE32); EXPORT_SYMBOL(GSC3280_LE32_TO_CPU); EXPORT_SYMBOL(GSC3280_BE32_TO_CPU); EXPORT_SYMBOL(GSC3280_CPU_TO_LE16); EXPORT_SYMBOL(GSC3280_CPU_TO_BE16); EXPORT_SYMBOL(GSC3280_LE16_TO_CPU); EXPORT_SYMBOL(GSC3280_BE16_TO_CPU); EXPORT_SYMBOL(GSC3280_READ_REG32); EXPORT_SYMBOL(GSC3280_WRITE_REG32); EXPORT_SYMBOL(GSC3280_MODIFY_REG32); #if 0 EXPORT_SYMBOL(GSC3280_READ_REG64); EXPORT_SYMBOL(GSC3280_WRITE_REG64); EXPORT_SYMBOL(GSC3280_MODIFY_REG64); #endif EXPORT_SYMBOL(GSC3280_SPINLOCK_ALLOC); EXPORT_SYMBOL(GSC3280_SPINLOCK_FREE); EXPORT_SYMBOL(GSC3280_SPINLOCK); EXPORT_SYMBOL(GSC3280_SPINUNLOCK); EXPORT_SYMBOL(GSC3280_SPINLOCK_IRQSAVE); EXPORT_SYMBOL(GSC3280_SPINUNLOCK_IRQRESTORE); EXPORT_SYMBOL(GSC3280_MUTEX_ALLOC); #if (!defined(GSC3280_LINUX) || !defined(CONFIG_DEBUG_MUTEXES)) EXPORT_SYMBOL(GSC3280_MUTEX_FREE); #endif EXPORT_SYMBOL(GSC3280_MUTEX_LOCK); EXPORT_SYMBOL(GSC3280_MUTEX_TRYLOCK); EXPORT_SYMBOL(GSC3280_MUTEX_UNLOCK); EXPORT_SYMBOL(GSC3280_UDELAY); EXPORT_SYMBOL(GSC3280_MDELAY); EXPORT_SYMBOL(GSC3280_MSLEEP); EXPORT_SYMBOL(GSC3280_TIME); EXPORT_SYMBOL(GSC3280_TIMER_ALLOC); EXPORT_SYMBOL(GSC3280_TIMER_FREE); EXPORT_SYMBOL(GSC3280_TIMER_SCHEDULE); EXPORT_SYMBOL(GSC3280_TIMER_CANCEL); EXPORT_SYMBOL(GSC3280_WAITQ_ALLOC); EXPORT_SYMBOL(GSC3280_WAITQ_FREE); EXPORT_SYMBOL(GSC3280_WAITQ_WAIT); EXPORT_SYMBOL(GSC3280_WAITQ_WAIT_TIMEOUT); EXPORT_SYMBOL(GSC3280_WAITQ_TRIGGER); EXPORT_SYMBOL(GSC3280_WAITQ_ABORT); EXPORT_SYMBOL(GSC3280_THREAD_RUN); EXPORT_SYMBOL(GSC3280_THREAD_STOP); EXPORT_SYMBOL(GSC3280_THREAD_SHOULD_STOP); EXPORT_SYMBOL(GSC3280_TASK_ALLOC); EXPORT_SYMBOL(GSC3280_TASK_FREE); EXPORT_SYMBOL(GSC3280_TASK_SCHEDULE); EXPORT_SYMBOL(GSC3280_WORKQ_WAIT_WORK_DONE); EXPORT_SYMBOL(GSC3280_WORKQ_ALLOC); EXPORT_SYMBOL(GSC3280_WORKQ_FREE); EXPORT_SYMBOL(GSC3280_WORKQ_SCHEDULE); EXPORT_SYMBOL(GSC3280_WORKQ_SCHEDULE_DELAYED); EXPORT_SYMBOL(GSC3280_WORKQ_PENDING); static int gsc3280_common_port_init_module(void) { int result = 0; printk(KERN_DEBUG "Module gsc3280_common_port init\n" ); #ifdef GSC3280_DEBUG_MEMORY result = gsc3280_memory_debug_start(NULL); if (result) { printk(KERN_ERR "gsc3280_memory_debug_start() failed with error %d\n", result); return result; } #endif #ifdef GSC3280_NOTIFYLIB result = gsc3280_alloc_notification_manager(NULL, NULL); if (result) { printk(KERN_ERR "gsc3280_alloc_notification_manager() failed with error %d\n", result); return result; } #endif return result; } static void gsc3280_common_port_exit_module(void) { printk(KERN_DEBUG "Module gsc3280_common_port exit\n" ); #ifdef GSC3280_NOTIFYLIB gsc3280_free_notification_manager(); #endif #ifdef GSC3280_DEBUG_MEMORY gsc3280_memory_debug_stop(); #endif } module_init(gsc3280_common_port_init_module); module_exit(gsc3280_common_port_exit_module); MODULE_DESCRIPTION("GSC3280 Common Library - Portable version"); MODULE_AUTHOR("BLX Inc."); MODULE_LICENSE ("GPL"); #endif /* GSC3280_LIBMODULE */