aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax_cmc/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wimax_cmc/control.c')
-rwxr-xr-xdrivers/net/wimax_cmc/control.c264
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);
+}