blob: b9f8a7aa24fedaa0825a48b83ad804af8ee65b4a [file] [log] [blame]
#include "headers.h"
static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
{
int status = urb->status;
struct bcm_interface_adapter *psIntfAdapter =
(struct bcm_interface_adapter *)urb->context;
struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
if (netif_msg_intr(Adapter))
pr_info(PFX "%s: interrupt status %d\n",
Adapter->dev->name, status);
if (Adapter->device_removed) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "Device has Got Removed.");
return;
}
if ((Adapter->bPreparingForLowPowerMode && Adapter->bDoSuspend) ||
psIntfAdapter->bSuspended ||
psIntfAdapter->bPreparingForBusSuspend) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Interrupt call back is called while suspending the device");
return;
}
switch (status) {
/* success */
case STATUS_SUCCESS:
if (urb->actual_length) {
if (psIntfAdapter->ulInterruptData[1] & 0xFF) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"Got USIM interrupt");
}
if (psIntfAdapter->ulInterruptData[1] & 0xFF00) {
atomic_set(&Adapter->CurrNumFreeTxDesc,
(psIntfAdapter->ulInterruptData[1] &
0xFF00) >> 8);
atomic_set(&Adapter->uiMBupdate, TRUE);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"TX mailbox contains %d",
atomic_read(&Adapter->CurrNumFreeTxDesc));
}
if (psIntfAdapter->ulInterruptData[1] >> 16) {
Adapter->CurrNumRecvDescs =
(psIntfAdapter->ulInterruptData[1] >> 16);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"RX mailbox contains %d",
Adapter->CurrNumRecvDescs);
InterfaceRx(psIntfAdapter);
}
if (Adapter->fw_download_done &&
!Adapter->downloadDDR &&
atomic_read(&Adapter->CurrNumFreeTxDesc)) {
psIntfAdapter->psAdapter->downloadDDR += 1;
wake_up(&Adapter->tx_packet_wait_queue);
}
if (!Adapter->waiting_to_fw_download_done) {
Adapter->waiting_to_fw_download_done = TRUE;
wake_up(&Adapter->ioctl_fw_dnld_wait_queue);
}
if (!atomic_read(&Adapter->TxPktAvail)) {
atomic_set(&Adapter->TxPktAvail, 1);
wake_up(&Adapter->tx_packet_wait_queue);
}
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "Firing interrupt in URB");
}
break;
case -ENOENT:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "URB has got disconnected....");
return;
case -EINPROGRESS:
/*
* This situation may happened when URBunlink is used. for
* detail check usb_unlink_urb documentation.
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Impossibe condition has occurred... something very bad is going on");
break;
/* return; */
case -EPIPE:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Interrupt IN endPoint has got halted/stalled...need to clear this");
Adapter->bEndPointHalted = TRUE;
wake_up(&Adapter->tx_packet_wait_queue);
urb->status = STATUS_SUCCESS;
return;
/* software-driven interface shutdown */
case -ECONNRESET: /* URB got unlinked */
case -ESHUTDOWN: /* hardware gone. this is the serious problem */
/*
* Occurs only when something happens with the
* host controller device
*/
case -ENODEV: /* Device got removed */
case -EINVAL:
/*
* Some thing very bad happened with the URB. No
* description is available.
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "interrupt urb error %d", status);
urb->status = STATUS_SUCCESS;
break;
/* return; */
default:
/*
* This is required to check what is the defaults conditions
* when it occurs..
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
"GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...",
status);
break;
}
StartInterruptUrb(psIntfAdapter);
}
int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter)
{
psIntfAdapter->psInterruptUrb = usb_alloc_urb(0, GFP_KERNEL);
if (!psIntfAdapter->psInterruptUrb) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"Cannot allocate interrupt urb");
return -ENOMEM;
}
psIntfAdapter->psInterruptUrb->transfer_buffer =
psIntfAdapter->ulInterruptData;
psIntfAdapter->psInterruptUrb->transfer_buffer_length =
sizeof(psIntfAdapter->ulInterruptData);
psIntfAdapter->sIntrIn.int_in_pipe = usb_rcvintpipe(psIntfAdapter->udev,
psIntfAdapter->sIntrIn.int_in_endpointAddr);
usb_fill_int_urb(psIntfAdapter->psInterruptUrb, psIntfAdapter->udev,
psIntfAdapter->sIntrIn.int_in_pipe,
psIntfAdapter->psInterruptUrb->transfer_buffer,
psIntfAdapter->psInterruptUrb->transfer_buffer_length,
read_int_callback, psIntfAdapter,
psIntfAdapter->sIntrIn.int_in_interval);
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "Interrupt Interval: %d\n",
psIntfAdapter->sIntrIn.int_in_interval);
return 0;
}
INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter)
{
INT status = 0;
if (!(psIntfAdapter->psAdapter->device_removed ||
psIntfAdapter->psAdapter->bEndPointHalted ||
psIntfAdapter->bSuspended ||
psIntfAdapter->bPreparingForBusSuspend ||
psIntfAdapter->psAdapter->StopAllXaction)) {
status =
usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC);
if (status) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,
"Cannot send inturb %d\n", status);
if (status == -EPIPE) {
psIntfAdapter->psAdapter->bEndPointHalted =
TRUE;
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
}
}
}
return status;
}