| 1 | #include "headers.h" |
| 2 | |
| 3 | /*this is transmit call-back(BULK OUT)*/ |
| 4 | static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) |
| 5 | { |
| 6 | struct bcm_usb_tcb *pTcb= (struct bcm_usb_tcb *)urb->context; |
| 7 | struct bcm_interface_adapter *psIntfAdapter = pTcb->psIntfAdapter; |
| 8 | struct bcm_link_request *pControlMsg = (struct bcm_link_request *)urb->transfer_buffer; |
| 9 | struct bcm_mini_adapter *psAdapter = psIntfAdapter->psAdapter ; |
| 10 | BOOLEAN bpowerDownMsg = FALSE ; |
| 11 | struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); |
| 12 | |
| 13 | if (unlikely(netif_msg_tx_done(Adapter))) |
| 14 | pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, urb->status); |
| 15 | |
| 16 | if(urb->status != STATUS_SUCCESS) |
| 17 | { |
| 18 | if(urb->status == -EPIPE) |
| 19 | { |
| 20 | psIntfAdapter->psAdapter->bEndPointHalted = TRUE ; |
| 21 | wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); |
| 22 | } |
| 23 | else |
| 24 | { |
| 25 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"Tx URB has got cancelled. status :%d", urb->status); |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | pTcb->bUsed = FALSE; |
| 30 | atomic_dec(&psIntfAdapter->uNumTcbUsed); |
| 31 | |
| 32 | |
| 33 | |
| 34 | if(TRUE == psAdapter->bPreparingForLowPowerMode) |
| 35 | { |
| 36 | |
| 37 | if(((pControlMsg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) && |
| 38 | (pControlMsg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE))) |
| 39 | |
| 40 | { |
| 41 | bpowerDownMsg = TRUE ; |
| 42 | //This covers the bus err while Idle Request msg sent down. |
| 43 | if(urb->status != STATUS_SUCCESS) |
| 44 | { |
| 45 | psAdapter->bPreparingForLowPowerMode = FALSE ; |
| 46 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"Idle Mode Request msg failed to reach to Modem"); |
| 47 | //Signalling the cntrl pkt path in Ioctl |
| 48 | wake_up(&psAdapter->lowpower_mode_wait_queue); |
| 49 | StartInterruptUrb(psIntfAdapter); |
| 50 | goto err_exit; |
| 51 | } |
| 52 | |
| 53 | if(psAdapter->bDoSuspend == FALSE) |
| 54 | { |
| 55 | psAdapter->IdleMode = TRUE; |
| 56 | //since going in Idle mode completed hence making this var false; |
| 57 | psAdapter->bPreparingForLowPowerMode = FALSE ; |
| 58 | |
| 59 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Host Entered in Idle Mode State..."); |
| 60 | //Signalling the cntrl pkt path in Ioctl |
| 61 | wake_up(&psAdapter->lowpower_mode_wait_queue); |
| 62 | } |
| 63 | |
| 64 | } |
| 65 | else if((pControlMsg->Leader.Status == LINK_UP_CONTROL_REQ) && |
| 66 | (pControlMsg->szData[0] == LINK_UP_ACK) && |
| 67 | (pControlMsg->szData[1] == LINK_SHUTDOWN_REQ_FROM_FIRMWARE) && |
| 68 | (pControlMsg->szData[2] == SHUTDOWN_ACK_FROM_DRIVER)) |
| 69 | { |
| 70 | //This covers the bus err while shutdown Request msg sent down. |
| 71 | if(urb->status != STATUS_SUCCESS) |
| 72 | { |
| 73 | psAdapter->bPreparingForLowPowerMode = FALSE ; |
| 74 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"Shutdown Request Msg failed to reach to Modem"); |
| 75 | //Signalling the cntrl pkt path in Ioctl |
| 76 | wake_up(&psAdapter->lowpower_mode_wait_queue); |
| 77 | StartInterruptUrb(psIntfAdapter); |
| 78 | goto err_exit; |
| 79 | } |
| 80 | |
| 81 | bpowerDownMsg = TRUE ; |
| 82 | if(psAdapter->bDoSuspend == FALSE) |
| 83 | { |
| 84 | psAdapter->bShutStatus = TRUE; |
| 85 | //since going in shutdown mode completed hence making this var false; |
| 86 | psAdapter->bPreparingForLowPowerMode = FALSE ; |
| 87 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"Host Entered in shutdown Mode State..."); |
| 88 | //Signalling the cntrl pkt path in Ioctl |
| 89 | wake_up(&psAdapter->lowpower_mode_wait_queue); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | if(psAdapter->bDoSuspend && bpowerDownMsg) |
| 94 | { |
| 95 | //issuing bus suspend request |
| 96 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"Issuing the Bus suspend request to USB stack"); |
| 97 | psIntfAdapter->bPreparingForBusSuspend = TRUE; |
| 98 | schedule_work(&psIntfAdapter->usbSuspendWork); |
| 99 | |
| 100 | } |
| 101 | |
| 102 | } |
| 103 | |
| 104 | err_exit : |
| 105 | usb_free_coherent(urb->dev, urb->transfer_buffer_length, |
| 106 | urb->transfer_buffer, urb->transfer_dma); |
| 107 | } |
| 108 | |
| 109 | |
| 110 | static struct bcm_usb_tcb *GetBulkOutTcb(struct bcm_interface_adapter *psIntfAdapter) |
| 111 | { |
| 112 | struct bcm_usb_tcb *pTcb = NULL; |
| 113 | UINT index = 0; |
| 114 | |
| 115 | if((atomic_read(&psIntfAdapter->uNumTcbUsed) < MAXIMUM_USB_TCB) && |
| 116 | (psIntfAdapter->psAdapter->StopAllXaction ==FALSE)) |
| 117 | { |
| 118 | index = atomic_read(&psIntfAdapter->uCurrTcb); |
| 119 | pTcb = &psIntfAdapter->asUsbTcb[index]; |
| 120 | pTcb->bUsed = TRUE; |
| 121 | pTcb->psIntfAdapter= psIntfAdapter; |
| 122 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got Tx desc %d used %d", |
| 123 | index, atomic_read(&psIntfAdapter->uNumTcbUsed)); |
| 124 | index = (index + 1) % MAXIMUM_USB_TCB; |
| 125 | atomic_set(&psIntfAdapter->uCurrTcb, index); |
| 126 | atomic_inc(&psIntfAdapter->uNumTcbUsed); |
| 127 | } |
| 128 | return pTcb; |
| 129 | } |
| 130 | |
| 131 | static int TransmitTcb(struct bcm_interface_adapter *psIntfAdapter, struct bcm_usb_tcb *pTcb, PVOID data, int len) |
| 132 | { |
| 133 | |
| 134 | struct urb *urb = pTcb->urb; |
| 135 | int retval = 0; |
| 136 | |
| 137 | urb->transfer_buffer = usb_alloc_coherent(psIntfAdapter->udev, len, |
| 138 | GFP_ATOMIC, &urb->transfer_dma); |
| 139 | if (!urb->transfer_buffer) |
| 140 | { |
| 141 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Error allocating memory\n"); |
| 142 | return -ENOMEM; |
| 143 | } |
| 144 | memcpy(urb->transfer_buffer, data, len); |
| 145 | urb->transfer_buffer_length = len; |
| 146 | |
| 147 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending Bulk out packet\n"); |
| 148 | //For T3B,INT OUT end point will be used as bulk out end point |
| 149 | if((psIntfAdapter->psAdapter->chip_id == T3B) && (psIntfAdapter->bHighSpeedDevice == TRUE)) |
| 150 | { |
| 151 | usb_fill_int_urb(urb, psIntfAdapter->udev, |
| 152 | psIntfAdapter->sBulkOut.bulk_out_pipe, |
| 153 | urb->transfer_buffer, len, write_bulk_callback, pTcb, |
| 154 | psIntfAdapter->sBulkOut.int_out_interval); |
| 155 | } |
| 156 | else |
| 157 | { |
| 158 | usb_fill_bulk_urb(urb, psIntfAdapter->udev, |
| 159 | psIntfAdapter->sBulkOut.bulk_out_pipe, |
| 160 | urb->transfer_buffer, len, write_bulk_callback, pTcb); |
| 161 | } |
| 162 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* For DMA transfer */ |
| 163 | |
| 164 | if(FALSE == psIntfAdapter->psAdapter->device_removed && |
| 165 | FALSE == psIntfAdapter->psAdapter->bEndPointHalted && |
| 166 | FALSE == psIntfAdapter->bSuspended && |
| 167 | FALSE == psIntfAdapter->bPreparingForBusSuspend) |
| 168 | { |
| 169 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
| 170 | if (retval) |
| 171 | { |
| 172 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "failed submitting write urb, error %d", retval); |
| 173 | if(retval == -EPIPE) |
| 174 | { |
| 175 | psIntfAdapter->psAdapter->bEndPointHalted = TRUE ; |
| 176 | wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | return retval; |
| 181 | } |
| 182 | |
| 183 | int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len) |
| 184 | { |
| 185 | struct bcm_usb_tcb *pTcb= NULL; |
| 186 | |
| 187 | struct bcm_interface_adapter *psIntfAdapter = (struct bcm_interface_adapter *)arg; |
| 188 | pTcb= GetBulkOutTcb(psIntfAdapter); |
| 189 | if(pTcb == NULL) |
| 190 | { |
| 191 | BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "No URB to transmit packet, dropping packet"); |
| 192 | return -EFAULT; |
| 193 | } |
| 194 | return TransmitTcb(psIntfAdapter, pTcb, data, len); |
| 195 | } |
| 196 | |
| 197 | |