static int mgnt_xmit_entry(struct sk_buff *skb, struct net_device *pnetdev) { u16 fc; int rc, len, pipe; unsigned int bmcst, tid, qsel; struct sk_buff *pxmit_skb; struct urb *urb; unsigned char *pxmitbuf; struct tx_desc *ptxdesc; struct ieee80211_hdr *tx_hdr; struct hostapd_priv *phostapdpriv = netdev_priv(pnetdev); _adapter *padapter = (_adapter *)phostapdpriv->padapter; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); struct dvobj_priv *pdvobj = &padapter->dvobjpriv; //printk("%s\n", __FUNCTION__); len = skb->len; tx_hdr = (struct ieee80211_hdr *)(skb->data); fc = le16_to_cpu(tx_hdr->frame_ctl); bmcst = IS_MCAST(tx_hdr->addr1); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) goto _exit; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) // http://www.mail-archive.com/[email protected]/msg17214.html pxmit_skb = dev_alloc_skb(len + TXDESC_SIZE); #else pxmit_skb = netdev_alloc_skb(pnetdev, len + TXDESC_SIZE); #endif if(!pxmit_skb) goto _exit; pxmitbuf = pxmit_skb->data; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { goto _exit; } // ----- fill tx desc ----- ptxdesc = (struct tx_desc *)pxmitbuf; _memset(ptxdesc, 0, sizeof(*ptxdesc)); //offset 0 ptxdesc->txdw0 |= cpu_to_le32(len&0x0000ffff); ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000);//default = 32 bytes for TX Desc ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); if(bmcst) { ptxdesc->txdw0 |= cpu_to_le32(BIT(24)); } //offset 4 ptxdesc->txdw1 |= cpu_to_le32(0x00);//MAC_ID ptxdesc->txdw1 |= cpu_to_le32((0x12<<QSEL_SHT)&0x00001f00); ptxdesc->txdw1 |= cpu_to_le32((0x06<< 16) & 0x000f0000);//b mode //offset 8 //offset 12 ptxdesc->txdw3 |= cpu_to_le32((le16_to_cpu(tx_hdr->seq_ctl)<<16)&0xffff0000); //offset 16 ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate //offset 20 cal_txdesc_chksum(ptxdesc); // ----- end of fill tx desc ----- // skb_put(pxmit_skb, len + TXDESC_SIZE); pxmitbuf = pxmitbuf + TXDESC_SIZE; _memcpy(pxmitbuf, skb->data, len); //printk("mgnt_xmit, len=%x\n", pxmit_skb->len); // ----- prepare urb for submit ----- //translate DMA FIFO addr to pipehandle //pipe = ffaddr2pipehdl(pdvobj, MGT_QUEUE_INX); pipe = usb_sndbulkpipe(pdvobj->pusbdev, pHalData->Queue2EPNum[(u8)MGT_QUEUE_INX]&0x0f); usb_fill_bulk_urb(urb, pdvobj->pusbdev, pipe, pxmit_skb->data, pxmit_skb->len, mgnt_xmit_cb, pxmit_skb); urb->transfer_flags |= URB_ZERO_PACKET; usb_anchor_urb(urb, &phostapdpriv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { usb_unanchor_urb(urb); kfree_skb(skb); } usb_free_urb(urb); _exit: dev_kfree_skb_any(skb); return 0; }
static void _update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, int sz) { uint qsel; _adapter *padapter = pxmitframe->padapter; struct ht_priv *phtpriv = &padapter->mlmepriv.htpriv; struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info; struct pkt_attrib *pattrib = &pxmitframe->attrib; sint bmcst = IS_MCAST(pattrib->ra); struct tx_desc *ptxdesc = (struct tx_desc*)pmem; _rtw_memset(ptxdesc, 0, sizeof(struct tx_desc)); //4 offset 0 ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff); ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00ff0000);//32 bytes for TX Desc if (bmcst) ptxdesc->txdw0 |= cpu_to_le32(BIT(24)); RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_update_txdesc: offset0=0x%08x\n", ptxdesc->txdw0)); //4 offset 4 // pkt_offset, unit:8 bytes padding if (pxmitframe->pkt_offset > 0) ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); #if USB_TX_AGGREGATION_92C if (pxmitframe->agg_num > 0) ptxdesc->txdw5 |= cpu_to_le32((pxmitframe->agg_num << 24) & 0xff000000); #endif if (pxmitframe->frame_tag == DATA_FRAMETAG) { //4 offset 4 ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x1f);//CAM_ID(MAC_ID) qsel = (uint)(pattrib->qsel & 0x0000001f); ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << 16) & 0x000f0000); fill_txdesc_sectype(pattrib, ptxdesc); if(pattrib->ampdu_en==_TRUE) ptxdesc->txdw1 |= cpu_to_le32(BIT(5));//AGG EN else ptxdesc->txdw1 |= cpu_to_le32(BIT(6));//AGG BK //4 offset 8 //4 offset 12 ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << 16) & 0xffff0000); //4 offset 16 , offset 20 if (pattrib->qos_en) ptxdesc->txdw4 |= cpu_to_le32(BIT(6));//QoS if ((pattrib->ether_type != 0x888e) && (pattrib->ether_type != 0x0806) && (pattrib->dhcp_pkt != 1)) { //Non EAP & ARP & DHCP type data packet fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); fill_txdesc_phy(pattrib, &ptxdesc->txdw4); ptxdesc->txdw4 |= cpu_to_le32(0x00000008);//RTS Rate=24M ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00); ptxdesc->txdw5 |= cpu_to_le32(0x0000000b);//DataRate - 54M if (0)//for driver dbg { ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate if (pattrib->ht_en) ptxdesc->txdw5 |= cpu_to_le32(BIT(6));//SGI ptxdesc->txdw5 |= cpu_to_le32(0x00000013);//init rate - mcs7 } } else { // EAP data packet and ARP packet. // Use the 1M data rate to send the EAP/ARP packet. // This will maybe make the handshake smooth. ptxdesc->txdw1 |= cpu_to_le32(BIT(6));//AGG BK ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate } //4 offset 24 #ifdef CONFIG_RTL8712_TCP_CSUM_OFFLOAD_TX if (pattrib->hw_tcp_csum == 1) { // ptxdesc->txdw6 = 0; // clear TCP_CHECKSUM and IP_CHECKSUM. It's zero already!! u8 ip_hdr_offset = 32 + pattrib->hdrlen + pattrib->iv_len + 8; ptxdesc->txdw7 = (1 << 31) | (ip_hdr_offset << 16); printk("ptxdesc->txdw7 = %08x\n", ptxdesc->txdw7); } #endif fill_txdesc_for_mp(pxmitframe, ptxdesc); } else if(pxmitframe->frame_tag == MGNT_FRAMETAG) { //printk("pxmitframe->frame_tag == MGNT_FRAMETAG\n"); //4 offset 4 ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x1f);//(MAC_ID) qsel = (uint)(pattrib->qsel&0x0000001f); ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<< 16) & 0x000f0000); //fill_txdesc_sectype(pattrib, ptxdesc); //4 offset 8 //4 offset 12 ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); //4 offset 16 ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate //4 offset 20 } else if(pxmitframe->frame_tag == TXAGG_FRAMETAG) { DBG_8192C("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); } else { DBG_8192C("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag); //4 offset 4 ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);//CAM_ID(MAC_ID) ptxdesc->txdw1 |= cpu_to_le32((6<< 16) & 0x000f0000);//raid //4 offset 8 //4 offset 12 ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << 16) & 0xffff0000); //4 offset 16 ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate //4 offset 20 } // 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. // (1) The sequence number of each non-Qos frame / broadcast / multicast / // mgnt frame should be controled by Hw because Fw will also send null data // which we cannot control when Fw LPS enable. // --> default enable non-Qos data sequense number. 2010.06.23. by tynli. // (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. // (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. // 2010.06.23. Added by tynli. if(!pattrib->qos_en) { ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); // Hw set sequence number ptxdesc->txdw3 |= cpu_to_le32((8 <<28)); //set bit3 to 1. Suugested by TimChen. 2009.12.29. } cal_txdesc_chksum(ptxdesc); }