/*=========================================================================== METHOD: GobiUSBNetStartXmit (Public Method) DESCRIPTION: Convert sk_buff to usb URB and queue for transmit PARAMETERS pNet [ I ] - Pointer to net device RETURN VALUE: NETDEV_TX_OK on success NETDEV_TX_BUSY on error ===========================================================================*/ int GobiUSBNetStartXmit( struct sk_buff * pSKB, struct net_device * pNet ) { unsigned long URBListFlags; struct sGobiUSBNet * pGobiDev; sAutoPM * pAutoPM; sURBList * pURBListEntry, ** ppURBListEnd; void * pURBData; struct usbnet * pDev = netdev_priv( pNet ); DBG( "\n" ); if (pDev == NULL || pDev->net == NULL) { DBG( "failed to get usbnet device\n" ); return NETDEV_TX_BUSY; } pGobiDev = (sGobiUSBNet *)pDev->data[0]; if (pGobiDev == NULL) { DBG( "failed to get QMIDevice\n" ); return NETDEV_TX_BUSY; } pAutoPM = &pGobiDev->mAutoPM; if (GobiTestDownReason( pGobiDev, DRIVER_SUSPENDED ) == true) { // Should not happen DBG( "device is suspended\n" ); dump_stack(); return NETDEV_TX_BUSY; } // Convert the sk_buff into a URB // Allocate URBListEntry pURBListEntry = kmalloc( sizeof( sURBList ), GFP_ATOMIC ); if (pURBListEntry == NULL) { DBG( "unable to allocate URBList memory\n" ); return NETDEV_TX_BUSY; } pURBListEntry->mpNext = NULL; // Allocate URB pURBListEntry->mpURB = usb_alloc_urb( 0, GFP_ATOMIC ); if (pURBListEntry->mpURB == NULL) { DBG( "unable to allocate URB\n" ); return NETDEV_TX_BUSY; } // Allocate URB transfer_buffer pURBData = kmalloc( pSKB->len, GFP_ATOMIC ); if (pURBData == NULL) { DBG( "unable to allocate URB data\n" ); return NETDEV_TX_BUSY; } // Fill will SKB's data memcpy( pURBData, pSKB->data, pSKB->len ); usb_fill_bulk_urb( pURBListEntry->mpURB, pGobiDev->mpNetDev->udev, pGobiDev->mpNetDev->out, pURBData, pSKB->len, GobiUSBNetURBCallback, pAutoPM ); // Aquire lock on URBList spin_lock_irqsave( &pAutoPM->mURBListLock, URBListFlags ); // Add URB to end of list ppURBListEnd = &pAutoPM->mpURBList; while ((*ppURBListEnd) != NULL) { ppURBListEnd = &(*ppURBListEnd)->mpNext; } *ppURBListEnd = pURBListEntry; spin_unlock_irqrestore( &pAutoPM->mURBListLock, URBListFlags ); complete( &pAutoPM->mThreadDoWork ); // Start transfer timer pNet->trans_start = jiffies; // Free SKB dev_kfree_skb_any( pSKB ); return NETDEV_TX_OK; }
/*=========================================================================== METHOD: GobiUSBNetStartXmit (Public Method) DESCRIPTION: Convert sk_buff to usb URB and queue for transmit PARAMETERS pNet [ I ] - Pointer to net device RETURN VALUE: NETDEV_TX_OK on success NETDEV_TX_BUSY on error ===========================================================================*/ int GobiUSBNetStartXmit( struct sk_buff * pSKB, struct net_device * pNet ) { unsigned long URBListFlags; struct sGobiUSBNet * pGobiDev; sAutoPM * pAutoPM; sURBList * pURBListEntry, ** ppURBListEnd; void * pURBData; struct usbnet * pDev = netdev_priv( pNet ); struct driver_info *info = pDev->driver_info; DBG( "\n" ); if (pDev == NULL || pDev->net == NULL) { DBG( "failed to get usbnet device\n" ); return NETDEV_TX_BUSY; } pGobiDev = (sGobiUSBNet *)pDev->data[0]; if (pGobiDev == NULL) { DBG( "failed to get QMIDevice\n" ); return NETDEV_TX_BUSY; } pAutoPM = &pGobiDev->mAutoPM; if( NULL == pSKB ) { DBG( "Buffer is NULL \n" ); return NETDEV_TX_BUSY; } if (GobiTestDownReason( pGobiDev, DRIVER_SUSPENDED ) == true) { // Should not happen DBG( "device is suspended\n" ); dump_stack(); return NETDEV_TX_BUSY; } // Convert the sk_buff into a URB // Check if buffer is full pGobiDev->tx_qlen = atomic_read( &pAutoPM->mURBListLen ); if ( pGobiDev->tx_qlen >= txQueueLength) { DBG( "not scheduling request, buffer is full\n" ); return NETDEV_TX_BUSY; } #if defined(DATA_MODE_RP) || defined(QOS_MODE) if (info->tx_fixup) { pSKB = info->tx_fixup( pDev, pSKB, GFP_ATOMIC); if (pSKB == NULL) { DBG( "unable to tx_fixup skb\n" ); return NETDEV_TX_BUSY; } } #endif // Allocate URBListEntry pURBListEntry = kmalloc( sizeof( sURBList ), GFP_ATOMIC ); if (pURBListEntry == NULL) { DBG( "unable to allocate URBList memory\n" ); if (pSKB) dev_kfree_skb_any ( pSKB ); return NETDEV_TX_BUSY; } pURBListEntry->mpNext = NULL; // Allocate URB pURBListEntry->mpURB = usb_alloc_urb( 0, GFP_ATOMIC ); if (pURBListEntry->mpURB == NULL) { DBG( "unable to allocate URB\n" ); // release all memory allocated by now if (pURBListEntry) kfree( pURBListEntry ); if (pSKB) dev_kfree_skb_any ( pSKB ); return NETDEV_TX_BUSY; } // Allocate URB transfer_buffer pURBData = kmalloc( pSKB->len, GFP_ATOMIC ); if (pURBData == NULL) { DBG( "unable to allocate URB data\n" ); // release all memory allocated by now if (pURBListEntry) { usb_free_urb(pURBListEntry->mpURB); #ifdef TX_URB_MONITOR if (URB_monitor) { URB_monitor(false); } #endif kfree( pURBListEntry ); } if (pSKB) dev_kfree_skb_any ( pSKB ); return NETDEV_TX_BUSY; } // Fill with SKB's data memcpy( pURBData, pSKB->data, pSKB->len ); usb_fill_bulk_urb( pURBListEntry->mpURB, pGobiDev->mpNetDev->udev, pGobiDev->mpNetDev->out, pURBData, pSKB->len, GobiUSBNetURBCallback, pAutoPM ); /* Handle the need to send a zero length packet and release the * transfer buffer */ pURBListEntry->mpURB->transfer_flags |= (URB_ZERO_PACKET | URB_FREE_BUFFER); // Aquire lock on URBList spin_lock_irqsave( &pAutoPM->mURBListLock, URBListFlags ); // Add URB to end of list ppURBListEnd = &pAutoPM->mpURBList; while ((*ppURBListEnd) != NULL) { ppURBListEnd = &(*ppURBListEnd)->mpNext; } *ppURBListEnd = pURBListEntry; atomic_inc( &pAutoPM->mURBListLen ); spin_unlock_irqrestore( &pAutoPM->mURBListLock, URBListFlags ); #ifdef TX_URB_MONITOR if (URB_monitor) { URB_monitor(true); } #endif complete( &pAutoPM->mThreadDoWork ); // Start transfer timer pNet->trans_start = jiffies; // Free SKB if (pSKB) dev_kfree_skb_any ( pSKB ); return NETDEV_TX_OK; }
/*=========================================================================== METHOD: GobiUSBNetStartXmit (Public Method) DESCRIPTION: Convert sk_buff to usb URB and queue for transmit PARAMETERS pNet [ I ] - Pointer to net device RETURN VALUE: NETDEV_TX_OK on success NETDEV_TX_BUSY on error ===========================================================================*/ int GobiUSBNetStartXmit( struct sk_buff * pSKB, struct net_device * pNet ) { unsigned long URBListFlags; struct sGobiUSBNet * pGobiDev; sAutoPM * pAutoPM; sURBList * pURBListEntry, ** ppURBListEnd; void * pURBData; struct usbnet * pDev = netdev_priv( pNet ); struct driver_info *info = pDev->driver_info; if (pDev == NULL || pDev->net == NULL) { DBG( "failed to get usbnet device\n" ); return NETDEV_TX_BUSY; } pGobiDev = (sGobiUSBNet *)pDev->data[0]; if (pGobiDev == NULL) { DBG( "failed to get QMIDevice\n" ); return NETDEV_TX_BUSY; } pAutoPM = &pGobiDev->mAutoPM; if (GobiTestDownReason( pGobiDev, DRIVER_SUSPENDED ) == true) { // Should not happen DBG( "device is suspended\n" ); dump_stack(); return NETDEV_TX_BUSY; } // Convert the sk_buff into a URB // Check if buffer is full if (atomic_read( &pAutoPM->mURBListLen ) >= txQueueLength) { DBG( "not scheduling request, buffer is full\n" ); return NETDEV_TX_BUSY; } // [[[ TimKang 20120716, add Raw IP mode if (info->tx_fixup) { pSKB = info->tx_fixup( pDev, pSKB, GFP_ATOMIC); if (pSKB == NULL) { DBG( "unable to tx_fixup skb\n" ); return NETDEV_TX_BUSY; } } // ]]] // Allocate URBListEntry pURBListEntry = kmalloc( sizeof( sURBList ), GFP_ATOMIC ); if (pURBListEntry == NULL) { DBG( "unable to allocate URBList memory\n" ); return NETDEV_TX_BUSY; } pURBListEntry->mpNext = NULL; // Allocate URB pURBListEntry->mpURB = usb_alloc_urb( 0, GFP_ATOMIC ); if (pURBListEntry->mpURB == NULL) { DBG( "unable to allocate URB\n" ); kfree( pURBListEntry ); return NETDEV_TX_BUSY; } // Allocate URB transfer_buffer pURBData = kmalloc( pSKB->len, GFP_ATOMIC ); if (pURBData == NULL) { DBG( "unable to allocate URB data\n" ); usb_free_urb( pURBListEntry->mpURB ); kfree( pURBListEntry ); return NETDEV_TX_BUSY; } // Fill will SKB's data memcpy( pURBData, pSKB->data, pSKB->len ); usb_fill_bulk_urb( pURBListEntry->mpURB, pGobiDev->mpNetDev->udev, pGobiDev->mpNetDev->out, pURBData, pSKB->len, GobiUSBNetURBCallback, pAutoPM ); // [[[ TimKang 20120202, add for packet statistics { #if (LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,31 )) struct net_device_stats * pStats = &(pGobiDev->mpNetDev->stats); #else struct net_device_stats * pStats = &(pGobiDev->mpNetDev->net->stats); #endif pStats->tx_packets++; pStats->tx_bytes += pSKB->len; } // ]]] // Free the transfer buffer on last reference dropped #if (LINUX_VERSION_CODE > KERNEL_VERSION( 2,6,24 )) pURBListEntry->mpURB->transfer_flags |= URB_FREE_BUFFER; #endif // Aquire lock on URBList spin_lock_irqsave( &pAutoPM->mURBListLock, URBListFlags ); // Add URB to end of list ppURBListEnd = &pAutoPM->mpURBList; while ((*ppURBListEnd) != NULL) { ppURBListEnd = &(*ppURBListEnd)->mpNext; } *ppURBListEnd = pURBListEntry; atomic_inc( &pAutoPM->mURBListLen ); spin_unlock_irqrestore( &pAutoPM->mURBListLock, URBListFlags ); complete( &pAutoPM->mThreadDoWork ); // Start transfer timer pNet->trans_start = jiffies; // Free SKB dev_kfree_skb_any( pSKB ); return NETDEV_TX_OK; }