diff options
author | Dorian Snyder <dastin1015@gmail.com> | 2013-06-12 02:24:45 -0700 |
---|---|---|
committer | Dorian Snyder <dastin1015@gmail.com> | 2013-06-20 00:06:04 -0700 |
commit | 4b2308ce699b9c599dd6e6acf57ac11f483381d9 (patch) | |
tree | 4c31179b06d094887b1c8ca70264cf8f184a5981 /drivers/net/wimax_cmc/control.c | |
parent | 855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d (diff) | |
download | kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.zip kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.gz kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.bz2 |
d710: initial support for the Epic 4G Touch (SPH-D710)
Change-Id: Iafbd9fb45253b02d539ac0ba114f57b3bf9eeed4
Diffstat (limited to 'drivers/net/wimax_cmc/control.c')
-rwxr-xr-x | drivers/net/wimax_cmc/control.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/drivers/net/wimax_cmc/control.c b/drivers/net/wimax_cmc/control.c new file mode 100755 index 0000000..b4abd60 --- /dev/null +++ b/drivers/net/wimax_cmc/control.c @@ -0,0 +1,264 @@ +/* + * control.c + * + * send and receive control packet and handle it + */ +#include "headers.h" + +u_int control_init(struct net_adapter *adapter) +{ + queue_init_list(adapter->ctl.q_received.head); + spin_lock_init(&adapter->ctl.q_received.lock); + + queue_init_list(adapter->ctl.apps.process_list); + spin_lock_init(&adapter->ctl.apps.lock); + + adapter->ctl.apps.ready = TRUE; + + return STATUS_SUCCESS; +} + +void control_remove(struct net_adapter *adapter) +{ + struct buffer_descriptor *dsc; + struct process_descriptor *process; + unsigned long flags; + /* Free the received control packets queue */ + while (!queue_empty(adapter->ctl.q_received.head)) { + /* queue is not empty */ + dump_debug("Freeing Control Receive Queue"); + dsc = (struct buffer_descriptor *) + queue_get_head(adapter->ctl.q_received.head); + if (!dsc) { + dump_debug("Fail...node is null"); + continue; + } + queue_remove_head(adapter->ctl.q_received.head); + if (dsc->buffer) + kfree(dsc->buffer); + if (dsc) + kfree(dsc); + } + + /* process list */ + if (adapter->ctl.apps.ready) { + if (!queue_empty(adapter->ctl.apps.process_list)) { + /* first time gethead needed to get the dsc nodes */ + process = (struct process_descriptor *)queue_get_head(adapter->ctl.apps.process_list); + spin_lock_irqsave(&adapter->ctl.apps.lock, flags); + while (process != NULL) { + if (process->irp) { + process->irp = FALSE; + wake_up_interruptible(&process->read_wait); + } + process = (struct process_descriptor *)process->node.next; + dump_debug("sangam dbg : waking processes"); + } + spin_unlock_irqrestore(&adapter->ctl.apps.lock, flags); + /* delay for the process release */ + msleep(100); + } + } + adapter->ctl.apps.ready = FALSE; +} + +/* add received packet to pending list */ +static void control_enqueue_buffer(struct net_adapter *adapter, + u_short type, void *buffer, u_long length) +{ + struct buffer_descriptor *dsc; + struct process_descriptor *process; + + /* Queue and wake read only if process exist. */ + process = process_by_type(adapter, type); + if (process) { + dsc = (struct buffer_descriptor *) + kmalloc(sizeof(struct buffer_descriptor), + GFP_ATOMIC); + if (dsc == NULL) { + dump_debug("dsc Memory Alloc Failure *****"); + return; + } + dsc->buffer = kmalloc(length, GFP_ATOMIC); + if (dsc->buffer == NULL) { + kfree(dsc); + dump_debug("dsc->buffer Memory Alloc Failure *****"); + return; + } + + memcpy(dsc->buffer, buffer, length); + /* fill out descriptor */ + dsc->length = length; + dsc->type = type; + /* add to pending list */ + queue_put_tail(adapter->ctl.q_received.head, dsc->node) + + if (process->irp) { + process->irp = FALSE; + wake_up_interruptible(&process->read_wait); + } + } else + dump_debug("Waiting process not found skip the packet"); +} + +/* receive control data */ +void control_recv(struct net_adapter *adapter, void *buffer, u_long length) +{ + struct eth_header *hdr; + + /* dump rx control frame */ + if (adapter->pdata->g_cfg->enable_dump_msg == 1) + dump_buffer("Control Rx", (u_char *)buffer + 12, length - 12); + + /* check halt flag */ + if (adapter->halted) + return; + + hdr = (struct eth_header *)buffer; + + /* not found, add to pending buffers list */ + spin_lock(&adapter->ctl.q_received.lock); + control_enqueue_buffer(adapter, hdr->type, buffer, length); + spin_unlock(&adapter->ctl.q_received.lock); +} + +u_int control_send(struct net_adapter *adapter, void *buffer, u_long length) +{ + if ((length + sizeof(struct hw_packet_header)) >= WIMAX_MAX_TOTAL_SIZE) + return STATUS_RESOURCES; + /* changed from SUCCESS return status */ + + return hw_send_data(adapter, buffer, length, CONTROL_PACKET); + +} + +struct process_descriptor *process_by_id(struct net_adapter *adapter, u_int id) +{ + struct process_descriptor *process; + + if (queue_empty(adapter->ctl.apps.process_list)) { + dump_debug("process_by_id: Empty process list"); + return NULL; + } + + /* first time gethead needed to get the dsc nodes */ + process = (struct process_descriptor *) + queue_get_head(adapter->ctl.apps.process_list); + while (process != NULL) { + if (process->id == id) /* process found */ + return process; + process = (struct process_descriptor *)process->node.next; + } + dump_debug("process_by_id: process not found"); + + return NULL; +} + +struct process_descriptor *process_by_type(struct net_adapter *adapter, + u_short type) +{ + struct process_descriptor *process; + + if (queue_empty(adapter->ctl.apps.process_list)) { + dump_debug("process_by_type: Empty process list"); + return NULL; + } + + /* first time gethead needed to get the dsc nodes */ + process = (struct process_descriptor *) + queue_get_head(adapter->ctl.apps.process_list); + while (process != NULL) { + if (process->type == type) /* process found */ + return process; + process = (struct process_descriptor *)process->node.next; + } + dump_debug("process_by_type: process not found"); + + return NULL; +} + +void remove_process(struct net_adapter *adapter, u_int id) +{ + struct process_descriptor *curElem; + struct process_descriptor *prevElem = NULL; + + if (queue_empty(adapter->ctl.apps.process_list)) + return; + + /* first time get head needed to get the dsc nodes */ + curElem = (struct process_descriptor *) + queue_get_head(adapter->ctl.apps.process_list); + + for ( ; curElem != NULL; prevElem = curElem, + curElem = (struct process_descriptor *) + curElem->node.next) { + if (curElem->id == id) { /* process found */ + if (prevElem == NULL) { + /* only one node present */ + (adapter->ctl.apps.process_list).next = + (((struct list_head *)curElem)->next); + if (!((adapter->ctl.apps.process_list).next)) { + /*rechain list pointer to next link*/ + dump_debug("sangam dbg first and only process delete"); + (adapter->ctl.apps.process_list).prev = NULL; + } + } else if (((struct list_head *)curElem)->next == + NULL) { + /* last node */ + dump_debug("sangam dbg only last packet"); + ((struct list_head *)prevElem)->next = NULL; + (adapter->ctl.apps.process_list).prev = + (struct list_head *)(prevElem); + } else { + /* middle node */ + dump_debug("sangam dbg middle node"); + ((struct list_head *)prevElem)->next = + ((struct list_head *)curElem)->next; + } + + kfree(curElem); + break; + } + } +} + +/* find buffer by buffer type */ +struct buffer_descriptor *buffer_by_type(struct list_head ListHead, + u_short type) +{ + struct buffer_descriptor *dsc; + + if (queue_empty(ListHead)) + return NULL; + + /* first time gethead needed to get the dsc nodes */ + dsc = (struct buffer_descriptor *)queue_get_head(ListHead); + while (dsc != NULL) { + if (dsc->type == type) /* process found */ + return dsc; + dsc = (struct buffer_descriptor *)dsc->node.next; + } + + return NULL; +} + +void dump_buffer(const char *desc, u_char *buffer, u_int len) +{ + char print_buf[256] = {0}; + char chr[8] = {0}; + int i; + + /* dump packets */ + u_char *b = buffer; + dump_debug("%s (%d) =>", desc, len); + + for (i = 0; i < len; i++) { + sprintf(chr, " %02x", b[i]); + strcat(print_buf, chr); + if (((i + 1) != len) && (i % 16 == 15)) { + dump_debug(print_buf); + memset(print_buf, 0x0, 256); + } + } + dump_debug(print_buf); +} |