summaryrefslogtreecommitdiffstats
path: root/drivers/staging/bcm/InterfaceRx.c
diff options
context:
space:
mode:
authorStephen Hemminger2010-09-08 23:46:36 +0200
committerGreg Kroah-Hartman2010-09-09 06:15:06 +0200
commitf8942e07a3db9d82e8fb11d3d494876b8bae9ff9 (patch)
tree2406636a4f9a4ac6b0bfc90e07aefa8b1b18b8ff /drivers/staging/bcm/InterfaceRx.c
parentStaging: keucr: fix up some coding style issues in the .h files (diff)
downloadkernel-qcow2-linux-f8942e07a3db9d82e8fb11d3d494876b8bae9ff9.tar.gz
kernel-qcow2-linux-f8942e07a3db9d82e8fb11d3d494876b8bae9ff9.tar.xz
kernel-qcow2-linux-f8942e07a3db9d82e8fb11d3d494876b8bae9ff9.zip
staging: Beeceem USB Wimax driver
The Sprint 4G network uses a Wimax dongle with Beecem chipset. The driver is typical of out of tree drivers, but maybe useful for people, and the hardware is readily available. Here is a staging ready version (i.e warts and all) 0. Started with Rel_5.2.7.3P1_USB from Sprint4GDeveloperPack-1.1 1. Consolidated files in staging 2. Remove Dos cr/lf 3. Remove unnecessary ioctl from usbbcm_fops Applied patches that were in the developer pack, surprising there were ones for 2.6.35 already. This is compile tested only, see TODO for what still needs to be done. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/bcm/InterfaceRx.c')
-rw-r--r--drivers/staging/bcm/InterfaceRx.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c
new file mode 100644
index 000000000000..6fee9684f2ef
--- /dev/null
+++ b/drivers/staging/bcm/InterfaceRx.c
@@ -0,0 +1,256 @@
+#include "headers.h"
+extern int SearchVcid(PMINI_ADAPTER , unsigned short);
+
+
+static PUSB_RCB
+GetBulkInRcb(PS_INTERFACE_ADAPTER psIntfAdapter)
+{
+ PUSB_RCB pRcb = NULL;
+ UINT index = 0;
+
+ if((atomic_read(&psIntfAdapter->uNumRcbUsed) < MAXIMUM_USB_RCB) &&
+ (psIntfAdapter->psAdapter->StopAllXaction == FALSE))
+ {
+ index = atomic_read(&psIntfAdapter->uCurrRcb);
+ pRcb = &psIntfAdapter->asUsbRcb[index];
+ pRcb->bUsed = TRUE;
+ pRcb->psIntfAdapter= psIntfAdapter;
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Got Rx desc %d used %d",
+ index, atomic_read(&psIntfAdapter->uNumRcbUsed));
+ index = (index + 1) % MAXIMUM_USB_RCB;
+ atomic_set(&psIntfAdapter->uCurrRcb, index);
+ atomic_inc(&psIntfAdapter->uNumRcbUsed);
+ }
+ return pRcb;
+}
+
+/*this is receive call back - when pkt avilable for receive (BULK IN- end point)*/
+static void read_bulk_callback(struct urb *urb)
+{
+ struct sk_buff *skb = NULL;
+ BOOLEAN bHeaderSupressionEnabled = FALSE;
+ int QueueIndex = NO_OF_QUEUES + 1;
+ UINT uiIndex=0;
+ int process_done = 1;
+ //int idleflag = 0 ;
+ PUSB_RCB pRcb = (PUSB_RCB)urb->context;
+ PS_INTERFACE_ADAPTER psIntfAdapter = pRcb->psIntfAdapter;
+ PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter;
+ PLEADER pLeader = urb->transfer_buffer;
+
+
+ #if 0
+ int *puiBuffer = NULL;
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+ do_gettimeofday(&tv);
+ #endif
+
+ if((Adapter->device_removed == TRUE) ||
+ (TRUE == Adapter->bEndPointHalted) ||
+ (0 == urb->actual_length)
+ )
+ {
+ pRcb->bUsed = FALSE;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+
+ if(urb->status != STATUS_SUCCESS)
+ {
+ if(urb->status == -EPIPE)
+ {
+ Adapter->bEndPointHalted = TRUE ;
+ wake_up(&Adapter->tx_packet_wait_queue);
+ }
+ else
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"Rx URB has got cancelled. status :%d", urb->status);
+ }
+ pRcb->bUsed = FALSE;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ urb->status = STATUS_SUCCESS ;
+ return ;
+ }
+
+ if(Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode))
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"device is going in low power mode while PMU option selected..hence rx packet should not be process");
+ return ;
+ }
+
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Read back done len %d\n", pLeader->PLength);
+ if(!pLeader->PLength)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Length 0");
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status,pLeader->PLength,pLeader->Vcid);
+ if(MAX_CNTL_PKT_SIZE < pLeader->PLength)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Corrupted leader length...%d\n",
+ pLeader->PLength);
+ atomic_inc(&Adapter->RxPacketDroppedCount);
+ atomic_add(pLeader->PLength, &Adapter->BadRxByteCount);
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+
+ QueueIndex = SearchVcid( Adapter,pLeader->Vcid);
+ if(QueueIndex < NO_OF_QUEUES)
+ {
+ bHeaderSupressionEnabled =
+ Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
+ bHeaderSupressionEnabled =
+ bHeaderSupressionEnabled & Adapter->bPHSEnabled;
+ }
+
+ skb = dev_alloc_skb (pLeader->PLength + SKB_RESERVE_PHS_BYTES + SKB_RESERVE_ETHERNET_HEADER);//2 //2 for allignment
+ if(!skb)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "NO SKBUFF!!! Dropping the Packet");
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+ /* If it is a control Packet, then call handle_bcm_packet ()*/
+ if((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) ||
+ (!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F)))
+ {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Recived control pkt...");
+ *(PUSHORT)skb->data = pLeader->Status;
+ memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer +
+ (sizeof(LEADER)), pLeader->PLength);
+ skb->len = pLeader->PLength + sizeof(USHORT);
+
+ spin_lock(&Adapter->control_queue_lock);
+ ENQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail,skb);
+ spin_unlock(&Adapter->control_queue_lock);
+
+ atomic_inc(&Adapter->cntrlpktCnt);
+ wake_up(&Adapter->process_rx_cntrlpkt);
+ }
+ else
+ {
+ /*
+ * Data Packet, Format a proper Ethernet Header
+ * and give it to the stack
+ */
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt...");
+ skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES);
+ memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(LEADER), pLeader->PLength);
+ skb->dev = Adapter->dev;
+
+ /* currently skb->len has extra ETH_HLEN bytes in the beginning */
+ skb_put (skb, pLeader->PLength + ETH_HLEN);
+ Adapter->PackInfo[QueueIndex].uiTotalRxBytes+=pLeader->PLength;
+ Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes+= pLeader->PLength;
+ atomic_add(pLeader->PLength, &Adapter->GoodRxByteCount);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt of len :0x%X", pLeader->PLength);
+
+ if(Adapter->if_up)
+ {
+ /* Moving ahead by ETH_HLEN to the data ptr as received from FW */
+ skb_pull(skb, ETH_HLEN);
+ PHSRecieve(Adapter, pLeader->Vcid, skb, &skb->len,
+ NULL,bHeaderSupressionEnabled);
+
+ if(!Adapter->PackInfo[QueueIndex].bEthCSSupport)
+ {
+ skb_push(skb, ETH_HLEN);
+
+ memcpy(skb->data, skb->dev->dev_addr, 6);
+ memcpy(skb->data+6, skb->dev->dev_addr, 6);
+ (*(skb->data+11))++;
+ *(skb->data+12) = 0x08;
+ *(skb->data+13) = 0x00;
+ pLeader->PLength+=ETH_HLEN;
+ }
+
+ skb->protocol = eth_type_trans(skb, Adapter->dev);
+ process_done = netif_rx(skb);
+ }
+ else
+ {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB...");
+ bcm_kfree_skb(skb);
+ }
+ atomic_inc(&Adapter->GoodRxPktCount);
+ for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++)
+ {
+ if((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1))
+ && (pLeader->PLength > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
+ Adapter->aRxPktSizeHist[uiIndex]++;
+ }
+ }
+ Adapter->PrevNumRecvDescs++;
+ pRcb->bUsed = FALSE;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+}
+
+static int ReceiveRcb(PS_INTERFACE_ADAPTER psIntfAdapter, PUSB_RCB pRcb)
+{
+ struct urb *urb = pRcb->urb;
+ int retval = 0;
+
+ usb_fill_bulk_urb(urb, psIntfAdapter->udev, usb_rcvbulkpipe(
+ psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_endpointAddr),
+ urb->transfer_buffer, BCM_USB_MAX_READ_LENGTH, read_bulk_callback,
+ pRcb);
+ if(FALSE == psIntfAdapter->psAdapter->device_removed &&
+ FALSE == psIntfAdapter->psAdapter->bEndPointHalted &&
+ FALSE == psIntfAdapter->bSuspended &&
+ FALSE == psIntfAdapter->bPreparingForBusSuspend)
+ {
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "failed submitting read urb, error %d", retval);
+ //if this return value is because of pipe halt. need to clear this.
+ if(retval == -EPIPE)
+ {
+ psIntfAdapter->psAdapter->bEndPointHalted = TRUE ;
+ wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
+ }
+
+ }
+ }
+ return retval;
+}
+
+/*
+Function: InterfaceRx
+
+Description: This is the hardware specific Function for Recieveing
+ data packet/control packets from the device.
+
+Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
+
+
+
+Return: TRUE - If Rx was successful.
+ Other - If an error occured.
+*/
+
+BOOLEAN InterfaceRx (PS_INTERFACE_ADAPTER psIntfAdapter)
+{
+ USHORT RxDescCount = NUM_RX_DESC - atomic_read(&psIntfAdapter->uNumRcbUsed);
+ PUSB_RCB pRcb = NULL;
+
+// RxDescCount = psIntfAdapter->psAdapter->CurrNumRecvDescs -
+// psIntfAdapter->psAdapter->PrevNumRecvDescs;
+ while(RxDescCount)
+ {
+ pRcb = GetBulkInRcb(psIntfAdapter);
+ if(pRcb == NULL)
+ {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Unable to get Rcb pointer");
+ return FALSE;
+ }
+ //atomic_inc(&psIntfAdapter->uNumRcbUsed);
+ ReceiveRcb(psIntfAdapter, pRcb);
+ RxDescCount--;
+ }
+ return TRUE;
+}
+