| #include "headers.h" |
| |
| static void prepare_low_power_mode(struct urb *urb, |
| struct bcm_interface_adapter *interface, |
| struct bcm_mini_adapter *ps_adapter, |
| struct bcm_mini_adapter *ad, |
| struct bcm_link_request *p_control_msg, |
| bool *b_power_down_msg) |
| { |
| if (((p_control_msg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) && |
| (p_control_msg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE))) { |
| |
| *b_power_down_msg = TRUE; |
| /* |
| * This covers the bus err while Idle Request msg |
| * sent down. |
| */ |
| if (urb->status != STATUS_SUCCESS) { |
| ps_adapter->bPreparingForLowPowerMode = false; |
| BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND, |
| DBG_LVL_ALL, |
| "Idle Mode Request msg failed to reach to Modem"); |
| /* Signalling the cntrl pkt path in Ioctl */ |
| wake_up(&ps_adapter->lowpower_mode_wait_queue); |
| StartInterruptUrb(interface); |
| return; |
| } |
| |
| if (ps_adapter->bDoSuspend == false) { |
| ps_adapter->IdleMode = TRUE; |
| /* since going in Idle mode completed hence making this var false */ |
| ps_adapter->bPreparingForLowPowerMode = false; |
| |
| BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND, |
| DBG_LVL_ALL, |
| "Host Entered in Idle Mode State..."); |
| /* Signalling the cntrl pkt path in Ioctl*/ |
| wake_up(&ps_adapter->lowpower_mode_wait_queue); |
| } |
| |
| } else if ((p_control_msg->Leader.Status == LINK_UP_CONTROL_REQ) && |
| (p_control_msg->szData[0] == LINK_UP_ACK) && |
| (p_control_msg->szData[1] == LINK_SHUTDOWN_REQ_FROM_FIRMWARE) && |
| (p_control_msg->szData[2] == SHUTDOWN_ACK_FROM_DRIVER)) { |
| /* |
| * This covers the bus err while shutdown Request |
| * msg sent down. |
| */ |
| if (urb->status != STATUS_SUCCESS) { |
| ps_adapter->bPreparingForLowPowerMode = false; |
| BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND, |
| DBG_LVL_ALL, |
| "Shutdown Request Msg failed to reach to Modem"); |
| /* Signalling the cntrl pkt path in Ioctl */ |
| wake_up(&ps_adapter->lowpower_mode_wait_queue); |
| StartInterruptUrb(interface); |
| return; |
| } |
| |
| *b_power_down_msg = TRUE; |
| if (ps_adapter->bDoSuspend == false) { |
| ps_adapter->bShutStatus = TRUE; |
| /* |
| * since going in shutdown mode completed hence |
| * making this var false |
| */ |
| ps_adapter->bPreparingForLowPowerMode = false; |
| BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND, |
| DBG_LVL_ALL, |
| "Host Entered in shutdown Mode State..."); |
| /* Signalling the cntrl pkt path in Ioctl */ |
| wake_up(&ps_adapter->lowpower_mode_wait_queue); |
| } |
| } |
| |
| if (ps_adapter->bDoSuspend && *b_power_down_msg) { |
| /* issuing bus suspend request */ |
| BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, |
| "Issuing the Bus suspend request to USB stack"); |
| interface->bPreparingForBusSuspend = TRUE; |
| schedule_work(&interface->usbSuspendWork); |
| } |
| } |
| |
| /*this is transmit call-back(BULK OUT)*/ |
| static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) |
| { |
| struct bcm_usb_tcb *pTcb = (struct bcm_usb_tcb *)urb->context; |
| struct bcm_interface_adapter *psIntfAdapter = pTcb->psIntfAdapter; |
| struct bcm_link_request *pControlMsg = |
| (struct bcm_link_request *)urb->transfer_buffer; |
| struct bcm_mini_adapter *psAdapter = psIntfAdapter->psAdapter; |
| bool bpowerDownMsg = false; |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); |
| |
| if (unlikely(netif_msg_tx_done(Adapter))) |
| pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, |
| urb->status); |
| |
| if (urb->status != STATUS_SUCCESS) { |
| if (urb->status == -EPIPE) { |
| psIntfAdapter->psAdapter->bEndPointHalted = TRUE; |
| wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); |
| } else { |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, |
| DBG_LVL_ALL, |
| "Tx URB has got cancelled. status :%d", |
| urb->status); |
| } |
| } |
| |
| pTcb->bUsed = false; |
| atomic_dec(&psIntfAdapter->uNumTcbUsed); |
| |
| if (TRUE == psAdapter->bPreparingForLowPowerMode) { |
| prepare_low_power_mode(urb, psIntfAdapter, psAdapter, Adapter, |
| pControlMsg, &bpowerDownMsg); |
| } |
| |
| usb_free_coherent(urb->dev, urb->transfer_buffer_length, |
| urb->transfer_buffer, urb->transfer_dma); |
| } |
| |
| |
| static struct bcm_usb_tcb *GetBulkOutTcb(struct bcm_interface_adapter *psIntfAdapter) |
| { |
| struct bcm_usb_tcb *pTcb = NULL; |
| UINT index = 0; |
| |
| if ((atomic_read(&psIntfAdapter->uNumTcbUsed) < MAXIMUM_USB_TCB) && |
| (psIntfAdapter->psAdapter->StopAllXaction == false)) { |
| index = atomic_read(&psIntfAdapter->uCurrTcb); |
| pTcb = &psIntfAdapter->asUsbTcb[index]; |
| pTcb->bUsed = TRUE; |
| pTcb->psIntfAdapter = psIntfAdapter; |
| BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX, |
| NEXT_SEND, DBG_LVL_ALL, |
| "Got Tx desc %d used %d", |
| index, |
| atomic_read(&psIntfAdapter->uNumTcbUsed)); |
| index = (index + 1) % MAXIMUM_USB_TCB; |
| atomic_set(&psIntfAdapter->uCurrTcb, index); |
| atomic_inc(&psIntfAdapter->uNumTcbUsed); |
| } |
| return pTcb; |
| } |
| |
| static int TransmitTcb(struct bcm_interface_adapter *psIntfAdapter, |
| struct bcm_usb_tcb *pTcb, PVOID data, int len) |
| { |
| |
| struct urb *urb = pTcb->urb; |
| int retval = 0; |
| |
| urb->transfer_buffer = usb_alloc_coherent(psIntfAdapter->udev, len, |
| GFP_ATOMIC, &urb->transfer_dma); |
| if (!urb->transfer_buffer) { |
| BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, |
| "Error allocating memory\n"); |
| return -ENOMEM; |
| } |
| memcpy(urb->transfer_buffer, data, len); |
| urb->transfer_buffer_length = len; |
| |
| BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX, NEXT_SEND, |
| DBG_LVL_ALL, "Sending Bulk out packet\n"); |
| /* For T3B,INT OUT end point will be used as bulk out end point */ |
| if ((psIntfAdapter->psAdapter->chip_id == T3B) && |
| (psIntfAdapter->bHighSpeedDevice == TRUE)) { |
| usb_fill_int_urb(urb, psIntfAdapter->udev, |
| psIntfAdapter->sBulkOut.bulk_out_pipe, |
| urb->transfer_buffer, len, write_bulk_callback, pTcb, |
| psIntfAdapter->sBulkOut.int_out_interval); |
| } else { |
| usb_fill_bulk_urb(urb, psIntfAdapter->udev, |
| psIntfAdapter->sBulkOut.bulk_out_pipe, |
| urb->transfer_buffer, len, write_bulk_callback, pTcb); |
| } |
| urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* For DMA transfer */ |
| |
| 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_TX, |
| NEXT_SEND, DBG_LVL_ALL, |
| "failed submitting write urb, error %d", |
| retval); |
| if (retval == -EPIPE) { |
| psIntfAdapter->psAdapter->bEndPointHalted = TRUE; |
| wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); |
| } |
| } |
| } |
| return retval; |
| } |
| |
| int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len) |
| { |
| struct bcm_usb_tcb *pTcb = NULL; |
| struct bcm_interface_adapter *psIntfAdapter = arg; |
| |
| pTcb = GetBulkOutTcb(psIntfAdapter); |
| if (pTcb == NULL) { |
| BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, |
| "No URB to transmit packet, dropping packet"); |
| return -EFAULT; |
| } |
| return TransmitTcb(psIntfAdapter, pTcb, data, len); |
| } |
| |