commit ee5b1aadfd5cda257337a9b9777114a10c18c31e Author: Ali Bahar Date: Sun Sep 4 03:14:21 2011 +0800 staging: r8712u: Merging Realtek's latest (v2.6.6). Various fixes. In r8712_generate_ie(), HT check is no longer done. Removed r8712_add_ht_addt_info(). Changes to defragmentation handling, and queue selection. Get TSSI command. Added an Ad-Hoc check to is_desired_network() r8712_ind_disconnect() now checks for Linked state. r8712_xmit_bh() now schedules an xmit tasklet. Signed-off-by: Ali Bahar Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c index f06addc..cc68d97 100644 --- a/drivers/staging/rtl8712/ieee80211.c +++ b/drivers/staging/rtl8712/ieee80211.c @@ -170,17 +170,11 @@ static uint r8712_get_rateset_len(u8 *rateset) return i; } -int r8712_generate_ie(struct registry_priv *pregistrypriv, - struct _adapter *padapter) +int r8712_generate_ie(struct registry_priv *pregistrypriv) { int sz = 0, rateLen; struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; u8 *ie = pdev_network->IEs; - struct ieee80211_ht_cap ht_capie; - struct ieee80211_ht_addt_info ht_addt_info; - unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; /*timestamp will be inserted by hardware*/ sz += 8; @@ -219,33 +213,6 @@ int r8712_generate_ie(struct registry_priv *pregistrypriv, /*IBSS Parameter Set*/ ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz); - if (pregistrypriv->ht_enable == 1) { - if (pqospriv->qos_option == 0) { - ie = r8712_set_ie(ie, _VENDOR_SPECIFIC_IE_, - _WMM_IE_Length_, WMM_IE, &sz); - pqospriv->qos_option = 1; - } - memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); - ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH | - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_TX_STBC | - IEEE80211_HT_CAP_MAX_AMSDU | - IEEE80211_HT_CAP_DSSSCCK40; - ht_capie.ampdu_params_info = (IEEE80211_HT_CAP_AMPDU_FACTOR & - 0x03) | (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00); - ie = r8712_set_ie(ie, _HT_CAPABILITY_IE_, - sizeof(struct ieee80211_ht_cap), - (unsigned char *)&ht_capie, &sz); - /*add HT info ie*/ - memset(&ht_addt_info, 0, - sizeof(struct ieee80211_ht_addt_info)); - /*need to add the HT additional IEs*/ - ht_addt_info.control_chan = pregistrypriv->channel; - ie = r8712_set_ie(ie, _HT_ADD_INFO_IE_, - sizeof(struct ieee80211_ht_addt_info), - (unsigned char *)&ht_addt_info, &sz); - } return sz; } diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h index d1d0868..3c0092b 100644 --- a/drivers/staging/rtl8712/ieee80211.h +++ b/drivers/staging/rtl8712/ieee80211.h @@ -137,7 +137,7 @@ struct ieee_ibss_seq { u8 mac[ETH_ALEN]; u16 seq_num; u16 frag_num; - unsigned int packet_time; + unsigned long packet_time; struct list_head list; }; @@ -669,7 +669,6 @@ struct ieee80211_txb { #define CRC_LENGTH 4U #define MAX_WPA_IE_LEN 128 -#define MAX_WPS_IE_LEN 512 #define NETWORK_EMPTY_ESSID (1<<0) #define NETWORK_HAS_OFDM (1<<1) @@ -789,8 +788,7 @@ int r8712_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len); int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); -int r8712_generate_ie(struct registry_priv *pregistrypriv, - struct _adapter *padapter); +int r8712_generate_ie(struct registry_priv *pregistrypriv); uint r8712_is_cckrates_included(u8 *rate); uint r8712_is_cckratesonly_included(u8 *rate); diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c index 961d6e5..9a75c6d 100644 --- a/drivers/staging/rtl8712/os_intfs.c +++ b/drivers/staging/rtl8712/os_intfs.c @@ -286,6 +286,9 @@ static u8 init_default_value(struct _adapter *padapter) pxmitpriv->vcs_type = pregistrypriv->vcs_type; pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; pxmitpriv->frag_len = pregistrypriv->frag_thresh; + /* mlme_priv */ + /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ + pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ /*ht_priv*/ { int i; diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index 625a8a0..6d69265 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -192,7 +192,7 @@ static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib, } else pattrib->tcpchk_valid = 0; /* invalid */ pattrib->mcs_rate = (u8)((le32_to_cpu(prxstat->rxdw3)) & 0x3f); - pattrib->htc = (u8)((le32_to_cpu(prxstat->rxdw3) >> 6) & 0x1); + pattrib->htc = (u8)((le32_to_cpu(prxstat->rxdw3) >> 14) & 0x1); /*Offset 16*/ /*Offset 20*/ /*phy_info*/ @@ -207,7 +207,7 @@ static union recv_frame *recvframe_defrag(struct _adapter *adapter, struct __queue *defrag_q) { struct list_head *plist, *phead; - u8 wlanhdr_offset; + u8 *data, wlanhdr_offset; u8 curfragnum; struct recv_frame_hdr *pfhdr, *pnfhdr; union recv_frame *prframe, *pnextrframe; @@ -224,22 +224,25 @@ static union recv_frame *recvframe_defrag(struct _adapter *adapter, /*the first fragment number must be 0 *free the whole queue*/ r8712_free_recvframe(prframe, pfree_recv_queue); - prframe = NULL; - goto exit; + r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); + return NULL; } - plist = get_next(phead); + curfragnum++; + plist = get_list_head(defrag_q); + plist = get_next(plist); + data = get_recvframe_data(prframe); while (end_of_queue_search(phead, plist) == false) { pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u); - /*check the fragment sequence (2nd ~n fragment frame) */ pnfhdr = &pnextrframe->u.hdr; - curfragnum++; + /*check the fragment sequence (2nd ~n fragment frame) */ if (curfragnum != pnfhdr->attrib.frag_num) { /* the fragment number must increase (after decache) * release the defrag_q & prframe */ r8712_free_recvframe(prframe, pfree_recv_queue); - prframe = NULL; - goto exit; + r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); + return NULL; } + curfragnum++; /* copy the 2nd~n fragment frame's payload to the first fragment * get the 2nd~last fragment frame's payload */ wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; @@ -252,7 +255,6 @@ static union recv_frame *recvframe_defrag(struct _adapter *adapter, pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; plist = get_next(plist); } -exit: /* free the defrag_q queue and return the prframe */ r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); return prframe; @@ -1074,7 +1076,7 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb) /* for first fragment packet, driver need allocate 1536 + * drvinfo_sz + RXDESC_SIZE to defrag packet. */ if ((mf == 1) && (frag == 0)) - alloc_sz = 1658; + alloc_sz = 1658;/*1658+6=1664, 1664 is 128 alignment.*/ else alloc_sz = tmp_len; /* 2 is for IP header 4 bytes alignment in QoS packet case. diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h index 6626c8f..8efbd1f 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.h +++ b/drivers/staging/rtl8712/rtl8712_recv.h @@ -29,7 +29,12 @@ #include "osdep_service.h" #include "drv_types.h" +/* Realtek's v2.6.6 reduced this to 4. However, under heavy network and CPU + * loads, even 8 receive buffers might not be enough; cutting it to 4 seemed + * unwise. + */ #define NR_RECVBUFF (8) + #define NR_PREALLOC_RECV_SKB (8) #define RXDESC_SIZE 24 #define RXDESC_OFFSET RXDESC_SIZE diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c index c1e4784..d09fbba 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/drivers/staging/rtl8712/rtl8712_xmit.c @@ -37,6 +37,7 @@ static void dump_xframe(struct _adapter *padapter, struct xmit_frame *pxmitframe); +static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz); sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag) { @@ -238,13 +239,24 @@ exit_dequeue_xframe_ex: void r8712_do_queue_select(struct _adapter *padapter, struct pkt_attrib *pattrib) { - u8 qsel = 0; + unsigned int qsel = 0; struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; if (pdvobj->nr_endpoint == 6) - qsel = pattrib->priority; - else if (pdvobj->nr_endpoint == 4) - qsel = pattrib->priority; + qsel = (unsigned int) pattrib->priority; + else if (pdvobj->nr_endpoint == 4) { + qsel = (unsigned int) pattrib->priority; + if (qsel == 0 || qsel == 3) + qsel = 3; + else if (qsel == 1 || qsel == 2) + qsel = 1; + else if (qsel == 4 || qsel == 5) + qsel = 5; + else if (qsel == 6 || qsel == 7) + qsel = 7; + else + qsel = 3; + } pattrib->qsel = qsel; } diff --git a/drivers/staging/rtl8712/rtl8712_xmit.h b/drivers/staging/rtl8712/rtl8712_xmit.h index 1e8f3fe..db52d13 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.h +++ b/drivers/staging/rtl8712/rtl8712_xmit.h @@ -64,6 +64,8 @@ #define OWN BIT(31) #define FSG BIT(27) #define LSG BIT(26) +#define TYPE_SHT (24) +#define TYPE_MSK (0x03000000) /*OFFSET 4*/ #define PKT_OFFSET_SZ (0) @@ -74,6 +76,7 @@ #define BMC BIT(7) #define BK BIT(30) #define AGG_EN BIT(29) +#define RTS_RC_SHT (16) /*OFFSET 12*/ #define SEQ_SHT (16) @@ -83,6 +86,8 @@ /*OFFSET 20*/ #define DISFB BIT(15) +#define RSVD6_MSK (0x00E00000) +#define RSVD6_SHT (21) struct tx_desc { /*DWORD 0*/ diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c index 2d8f48c..d77388b 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.c +++ b/drivers/staging/rtl8712/rtl871x_cmd.c @@ -240,7 +240,7 @@ u8 r8712_sitesurvey_cmd(struct _adapter *padapter, init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); psurveyPara->bsslimit = cpu_to_le32(48); - psurveyPara->passive_mode = cpu_to_le32(1); + psurveyPara->passive_mode = cpu_to_le32(pmlmepriv->passive_mode); psurveyPara->ss_ssidlen = 0; memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1); if ((pssid != NULL) && (pssid->SsidLength)) { @@ -251,6 +251,7 @@ u8 r8712_sitesurvey_cmd(struct _adapter *padapter, r8712_enqueue_cmd(pcmdpriv, ph2c); _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); padapter->ledpriv.LedControlHandler(padapter, LED_CTL_SITE_SURVEY); + padapter->blnEnableRxFF0Filter = 0; return _SUCCESS; } @@ -760,6 +761,33 @@ u8 r8712_setrttbl_cmd(struct _adapter *padapter, return _SUCCESS; } +u8 r8712_gettssi_cmd(struct _adapter *padapter, u8 offset, u8 *pval) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct readTSSI_parm *prdtssiparm; + + ph2c = (struct cmd_obj *)_malloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) + return _FAIL; + prdtssiparm = (struct readTSSI_parm *) + _malloc(sizeof(struct readTSSI_parm)); + if (prdtssiparm == NULL) { + kfree((unsigned char *) ph2c); + return _FAIL; + } + _init_listhead(&ph2c->list); + ph2c->cmdcode = GEN_CMD_CODE(_ReadTSSI); + ph2c->parmbuf = (unsigned char *)prdtssiparm; + ph2c->cmdsz = sizeof(struct readTSSI_parm); + ph2c->rsp = pval; + ph2c->rspsz = sizeof(struct readTSSI_rsp); + + prdtssiparm->offset = offset; + r8712_enqueue_cmd(pcmdpriv, ph2c); + return _SUCCESS; +} + u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr) { struct cmd_priv *pcmdpriv = &padapter->cmdpriv; diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 866554d..c475b96 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -52,6 +52,8 @@ static sint _init_mlme_priv(struct _adapter *padapter) pmlmepriv->fw_state = 0; pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; + /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ + pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ spin_lock_init(&(pmlmepriv->lock)); spin_lock_init(&(pmlmepriv->lock2)); _init_queue(&(pmlmepriv->free_bss_pool)); @@ -485,6 +487,12 @@ static int is_desired_network(struct _adapter *adapter, if ((psecuritypriv->PrivacyAlgrthm != _NO_PRIVACY_) && (pnetwork->network.Privacy == 0)) bselected = false; + if (check_fwstate(&adapter->mlmepriv, WIFI_ADHOC_STATE) == true) { + if (pnetwork->network.InfrastructureMode != + adapter->mlmepriv.cur_network.network. + InfrastructureMode) + bselected = false; + } return bselected; } @@ -683,9 +691,11 @@ void r8712_ind_disconnect(struct _adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - _clr_fwstate_(pmlmepriv, _FW_LINKED); - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); - r8712_os_indicate_disconnect(padapter); + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + _clr_fwstate_(pmlmepriv, _FW_LINKED); + padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); + r8712_os_indicate_disconnect(padapter); + } if (padapter->pwrctrlpriv.pwr_mode != padapter->registrypriv.power_mgnt) { _cancel_timer_ex(&pmlmepriv->dhcp_timer); @@ -718,9 +728,9 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) if (sizeof(struct list_head) == 4 * sizeof(u32)) { pnetwork = (struct wlan_network *) - _malloc(sizeof(struct wlan_network)); + _malloc(sizeof(struct wlan_network)); memcpy((u8 *)pnetwork+16, (u8 *)pbuf + 8, - sizeof(struct wlan_network) - 16); + sizeof(struct wlan_network) - 16); } else pnetwork = (struct wlan_network *)pbuf; @@ -1657,7 +1667,7 @@ void r8712_update_registrypriv_dev_network(struct _adapter *adapter) /* 1. Supported rates * 2. IE */ - sz = r8712_generate_ie(pregistrypriv, adapter); + sz = r8712_generate_ie(pregistrypriv); pdev_network->IELength = sz; pdev_network->Length = r8712_get_ndis_wlan_bssid_ex_sz( (struct ndis_wlan_bssid_ex *)pdev_network); @@ -1802,39 +1812,3 @@ void r8712_issue_addbareq_cmd(struct _adapter *padapter, int priority) } } } - -/*the function is >= passive_level*/ -unsigned int r8712_add_ht_addt_info(struct _adapter *padapter, - u8 *in_ie, u8 *out_ie, - uint in_len, uint *pout_len) -{ - u32 ielen, out_len = 0; - unsigned char *p, *pframe; - struct ieee80211_ht_addt_info ht_addt_info; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - out_len = *pout_len; - - if (pregistrypriv->ht_enable == 1) { - p = r8712_get_ie(in_ie+12, _HT_ADD_INFO_IE_, - &ielen, in_len - 12); - if (p && (ielen > 0)) { - ; /* dummy branch */ - } else { - if (p == NULL) { - int sz = sizeof(struct ieee80211_ht_addt_info); - memset(&ht_addt_info, 0, sz); - /*need to add the HT additional IEs*/ - ht_addt_info.control_chan = - pregistrypriv->channel; - pframe = r8712_set_ie(out_ie + out_len, - _HT_ADD_INFO_IE_, - sz, - (unsigned char *)&ht_addt_info, - pout_len); - } - } - } - return phtpriv->ht_option; -} diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h index 8198778..a1dccec 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.h +++ b/drivers/staging/rtl8712/rtl871x_xmit.h @@ -93,9 +93,9 @@ struct pkt_attrib { u16 seqnum; u16 ether_type; - u32 pktlen; /* the original 802.3 pkt raw_data len + u16 pktlen; /* the original 802.3 pkt raw_data len * (not include ether_hdr data) */ - u32 last_txcmdsz; + u16 last_txcmdsz; u8 pkt_hdrlen; /*the original 802.3 pkt header len*/ u8 hdrlen; /*the WLAN Header Len*/ @@ -225,6 +225,9 @@ struct xmit_priv { struct semaphore tx_retevt;/*all tx return event;*/ u8 txirp_cnt; struct tasklet_struct xmit_tasklet; + _workitem xmit_pipe4_reset_wi; + _workitem xmit_pipe6_reset_wi; + _workitem xmit_piped_reset_wi; /*per AC pending irp*/ int beq_cnt; int bkq_cnt; diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h index 2ac8d33..48d6a14 100644 --- a/drivers/staging/rtl8712/sta_info.h +++ b/drivers/staging/rtl8712/sta_info.h @@ -63,8 +63,8 @@ struct sta_info { struct sta_recv_priv sta_recvpriv; uint state; uint aid; - u8 mac_id; - u8 qos_option; + uint mac_id; + uint qos_option; u8 hwaddr[ETH_ALEN]; uint ieee8021x_blocked; /*0: allowed, 1:blocked */ uint XPrivacy; /*aes, tkip...*/ diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 3bcb669..0a2f274 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -368,23 +368,25 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, struct _adapter *padapter = NULL; struct dvobj_priv *pdvobjpriv; struct net_device *pnetdev; + struct usb_device *udev; printk(KERN_INFO "r8712u: DriverVersion: %s\n", DRVER); /* In this probe function, O.S. will provide the usb interface pointer * to driver. We have to increase the reference count of the usb device * structure by using the usb_get_dev function. */ - usb_get_dev(interface_to_usbdev(pusb_intf)); + udev = interface_to_usbdev(pusb_intf); + usb_get_dev(udev); pintf = pusb_intf; /* step 1. */ pnetdev = r8712_init_netdev(); if (!pnetdev) goto error; - padapter = (struct _adapter *)netdev_priv(pnetdev); + padapter = netdev_priv(pnetdev); disable_ht_for_spec_devid(pdid, padapter); pdvobjpriv = &padapter->dvobjpriv; pdvobjpriv->padapter = padapter; - padapter->dvobjpriv.pusbdev = interface_to_usbdev(pusb_intf); + padapter->dvobjpriv.pusbdev = udev; usb_set_intfdata(pusb_intf, pnetdev); SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); /* step 2. */ @@ -594,9 +596,10 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, /* step 6. Tell the network stack we exist */ if (register_netdev(pnetdev) != 0) goto error; + spin_lock_init(&padapter->lockRxFF0Filter); return 0; error: - usb_put_dev(interface_to_usbdev(pusb_intf)); + usb_put_dev(udev); usb_set_intfdata(pusb_intf, NULL); if (padapter->dvobj_deinit != NULL) padapter->dvobj_deinit(padapter); @@ -613,6 +616,7 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf) struct _adapter *padapter = netdev_priv(pnetdev); struct usb_device *udev = interface_to_usbdev(pusb_intf); + usb_set_intfdata(pusb_intf, NULL); if (padapter) { if (drvpriv.drv_registered == true) padapter->bSurpriseRemoved = true; diff --git a/drivers/staging/rtl8712/usb_ops_linux.c b/drivers/staging/rtl8712/usb_ops_linux.c index b796c6b..24e1ec5 100644 --- a/drivers/staging/rtl8712/usb_ops_linux.c +++ b/drivers/staging/rtl8712/usb_ops_linux.c @@ -334,17 +334,16 @@ void r8712_xmit_bh(void *priv) struct _adapter *padapter = (struct _adapter *)priv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - while (1) { - if ((padapter->bDriverStopped == true) || - (padapter->bSurpriseRemoved == true)) { - printk(KERN_ERR "r8712u: xmit_bh => bDriverStopped" - " or bSurpriseRemoved\n"); - break; - } - ret = r8712_xmitframe_complete(padapter, pxmitpriv, NULL); - if (ret == false) - break; + if ((padapter->bDriverStopped == true) || + (padapter->bSurpriseRemoved == true)) { + printk(KERN_ERR "r8712u: xmit_bh => bDriverStopped" + " or bSurpriseRemoved\n"); + return; } + ret = r8712_xmitframe_complete(padapter, pxmitpriv, NULL); + if (ret == false) + return; + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); } static void usb_write_port_complete(struct urb *purb)