| #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 == TRUE) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Device has Got Removed."); |
| return ; |
| } |
| |
| if(((Adapter->bPreparingForLowPowerMode == TRUE) && (Adapter->bDoSuspend == TRUE)) || |
| 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 ; |
| } |
| |
| //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "interrupt urb status %d", status); |
| 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(false == 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( false == psIntfAdapter->psAdapter->device_removed && |
| false == psIntfAdapter->psAdapter->bEndPointHalted && |
| false == psIntfAdapter->bSuspended && |
| false == psIntfAdapter->bPreparingForBusSuspend && |
| false == 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 int urb %d\n", status); |
| if(status == -EPIPE) |
| { |
| psIntfAdapter->psAdapter->bEndPointHalted = TRUE ; |
| wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); |
| } |
| } |
| } |
| return status; |
| } |
| |