Commit | Line | Data |
---|---|---|
8dba599d FS |
1 | /* |
2 | * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. | |
3 | * | |
4 | * Module: r819xusb_cmdpkt.c | |
5 | * (RTL8190 TX/RX command packet handler Source C File) | |
6 | * | |
7 | * Note: The module is responsible for handling TX and RX command packet. | |
8 | * 1.TX: Send set and query configuration command packet. | |
9 | * 2.RX: Receive tx feedback, beacon state, query configuration, command packet. | |
10 | */ | |
5f53d8ca JC |
11 | #include "r8192U.h" |
12 | #include "r819xU_cmdpkt.h" | |
8dba599d FS |
13 | |
14 | bool SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen) | |
5f53d8ca JC |
15 | { |
16 | bool rtStatus = true; | |
17 | struct r8192_priv *priv = ieee80211_priv(dev); | |
18 | struct sk_buff *skb; | |
19 | cb_desc *tcb_desc; | |
20 | unsigned char *ptr_buf; | |
5f53d8ca | 21 | |
8dba599d | 22 | /* PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); */ |
5f53d8ca | 23 | |
8dba599d FS |
24 | /* |
25 | * Get TCB and local buffer from common pool. | |
26 | * (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) | |
27 | */ | |
5f53d8ca | 28 | skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4); |
199ef62a FS |
29 | if (skb == NULL) { |
30 | RT_TRACE(COMP_ERR, "(%s): unable to alloc skb buffer\n", | |
31 | __func__); | |
32 | rtStatus = false; | |
33 | return rtStatus; | |
34 | } | |
8dba599d FS |
35 | memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); |
36 | tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); | |
5f53d8ca JC |
37 | tcb_desc->queue_index = TXCMD_QUEUE; |
38 | tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL; | |
39 | tcb_desc->bLastIniPkt = 0; | |
40 | skb_reserve(skb, USB_HWDESC_HEADER_LEN); | |
41 | ptr_buf = skb_put(skb, DataLen); | |
8dba599d FS |
42 | memcpy(ptr_buf, pData, DataLen); |
43 | tcb_desc->txbuf_size = (u16)DataLen; | |
44 | ||
45 | if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) || | |
46 | (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) || | |
47 | (priv->ieee80211->queue_stop)) { | |
48 | RT_TRACE(COMP_FIRMWARE, "NULL packet => tx full\n"); | |
5f53d8ca JC |
49 | skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); |
50 | } else { | |
8dba599d | 51 | priv->ieee80211->softmac_hard_start_xmit(skb, dev); |
5f53d8ca JC |
52 | } |
53 | ||
54 | //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); | |
55 | return rtStatus; | |
56 | } | |
57 | ||
8dba599d | 58 | /* |
5f53d8ca JC |
59 | * Function: cmpk_message_handle_tx() |
60 | * | |
61 | * Overview: Driver internal module can call the API to send message to | |
8dba599d FS |
62 | * firmware side. For example, you can send a debug command packet. |
63 | * Or you can send a request for FW to modify RLX4181 LBUS HW bank. | |
64 | * Otherwise, you can change MAC/PHT/RF register by firmware at | |
65 | * run time. We do not support message more than one segment now. | |
5f53d8ca JC |
66 | * |
67 | * Input: NONE | |
68 | * | |
69 | * Output: NONE | |
70 | * | |
71 | * Return: NONE | |
8dba599d | 72 | */ |
5f53d8ca JC |
73 | extern bool cmpk_message_handle_tx( |
74 | struct net_device *dev, | |
8dba599d | 75 | u8 *codevirtualaddress, |
5f53d8ca JC |
76 | u32 packettype, |
77 | u32 buffer_len) | |
78 | { | |
8dba599d | 79 | bool rt_status = true; |
5f53d8ca | 80 | return rt_status; |
8dba599d | 81 | } |
5f53d8ca | 82 | |
8dba599d FS |
83 | /* |
84 | * Function: cmpk_counttxstatistic() | |
85 | */ | |
5f53d8ca | 86 | static void |
8dba599d | 87 | cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb) |
5f53d8ca JC |
88 | { |
89 | struct r8192_priv *priv = ieee80211_priv(dev); | |
90 | #ifdef ENABLE_PS | |
8dba599d | 91 | RT_RF_POWER_STATE rtState; |
5f53d8ca | 92 | |
8dba599d FS |
93 | pAdapter->HalFunc.GetHwRegHandler(pAdapter, |
94 | HW_VAR_RF_STATE, | |
95 | (pu1Byte)(&rtState)); | |
5f53d8ca | 96 | |
8dba599d FS |
97 | /* |
98 | * When RF is off, we should not count the packet for hw/sw synchronize | |
99 | * reason, ie. there may be a duration while sw switch is changed and hw | |
100 | * switch is being changed. | |
101 | */ | |
5f53d8ca | 102 | if (rtState == eRfOff) |
5f53d8ca | 103 | return; |
5f53d8ca JC |
104 | #endif |
105 | ||
106 | #ifdef TODO | |
8dba599d | 107 | if (pAdapter->bInHctTest) |
5f53d8ca JC |
108 | return; |
109 | #endif | |
8dba599d FS |
110 | /* |
111 | * We can not know the packet length and transmit type: | |
112 | * broadcast or uni or multicast. | |
113 | * So the relative statistics must be collected in tx feedback info | |
114 | */ | |
115 | if (pstx_fb->tok) { | |
5f53d8ca JC |
116 | priv->stats.txfeedbackok++; |
117 | priv->stats.txoktotal++; | |
118 | priv->stats.txokbytestotal += pstx_fb->pkt_length; | |
119 | priv->stats.txokinperiod++; | |
5f53d8ca | 120 | /* We can not make sure broadcast/multicast or unicast mode. */ |
8dba599d | 121 | if (pstx_fb->pkt_type == PACKET_MULTICAST) { |
5f53d8ca JC |
122 | priv->stats.txmulticast++; |
123 | priv->stats.txbytesmulticast += pstx_fb->pkt_length; | |
8dba599d | 124 | } else if (pstx_fb->pkt_type == PACKET_BROADCAST) { |
5f53d8ca JC |
125 | priv->stats.txbroadcast++; |
126 | priv->stats.txbytesbroadcast += pstx_fb->pkt_length; | |
8dba599d | 127 | } else { |
5f53d8ca JC |
128 | priv->stats.txunicast++; |
129 | priv->stats.txbytesunicast += pstx_fb->pkt_length; | |
130 | } | |
8dba599d | 131 | } else { |
5f53d8ca JC |
132 | priv->stats.txfeedbackfail++; |
133 | priv->stats.txerrtotal++; | |
134 | priv->stats.txerrbytestotal += pstx_fb->pkt_length; | |
5f53d8ca JC |
135 | /* We can not make sure broadcast/multicast or unicast mode. */ |
136 | if (pstx_fb->pkt_type == PACKET_MULTICAST) | |
5f53d8ca | 137 | priv->stats.txerrmulticast++; |
5f53d8ca | 138 | else if (pstx_fb->pkt_type == PACKET_BROADCAST) |
5f53d8ca | 139 | priv->stats.txerrbroadcast++; |
5f53d8ca | 140 | else |
5f53d8ca | 141 | priv->stats.txerrunicast++; |
5f53d8ca | 142 | } |
5f53d8ca JC |
143 | priv->stats.txretrycount += pstx_fb->retry_cnt; |
144 | priv->stats.txfeedbackretry += pstx_fb->retry_cnt; | |
8dba599d | 145 | } |
5f53d8ca | 146 | |
8dba599d | 147 | /* |
5f53d8ca JC |
148 | * Function: cmpk_handle_tx_feedback() |
149 | * | |
150 | * Overview: The function is responsible for extract the message inside TX | |
8dba599d FS |
151 | * feedbck message from firmware. It will contain dedicated info in |
152 | * ws-06-0063-rtl8190-command-packet-specification. Please | |
153 | * refer to chapter "TX Feedback Element". We have to read 20 bytes | |
154 | * in the command packet. | |
5f53d8ca JC |
155 | * |
156 | * Input: struct net_device * dev | |
8dba599d | 157 | * u8 *pmsg - Msg Ptr of the command packet. |
5f53d8ca JC |
158 | * |
159 | * Output: NONE | |
160 | * | |
161 | * Return: NONE | |
8dba599d FS |
162 | */ |
163 | static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg) | |
5f53d8ca JC |
164 | { |
165 | struct r8192_priv *priv = ieee80211_priv(dev); | |
8dba599d | 166 | cmpk_txfb_t rx_tx_fb; |
5f53d8ca JC |
167 | |
168 | priv->stats.txfeedback++; | |
169 | ||
5f53d8ca | 170 | /* 1. Extract TX feedback info from RFD to temp structure buffer. */ |
8dba599d | 171 | memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t)); |
35c1b462 | 172 | |
5f53d8ca JC |
173 | /* 2. Use tx feedback info to count TX statistics. */ |
174 | cmpk_count_txstatistic(dev, &rx_tx_fb); | |
8dba599d | 175 | } |
35c1b462 | 176 | |
8dba599d | 177 | void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev) |
5f53d8ca JC |
178 | { |
179 | struct r8192_priv *priv = ieee80211_priv(dev); | |
180 | u16 tx_rate; | |
5f53d8ca | 181 | |
8dba599d FS |
182 | if (priv->ieee80211->current_network.mode == IEEE_A || |
183 | priv->ieee80211->current_network.mode == IEEE_N_5G || | |
184 | (priv->ieee80211->current_network.mode == IEEE_N_24G && | |
185 | (!priv->ieee80211->pHTInfo->bCurSuppCCK))) { | |
186 | tx_rate = 60; | |
187 | DMESG("send beacon frame tx rate is 6Mbpm\n"); | |
188 | } else { | |
189 | tx_rate = 10; | |
190 | DMESG("send beacon frame tx rate is 1Mbpm\n"); | |
5f53d8ca | 191 | } |
8dba599d | 192 | rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */ |
5f53d8ca JC |
193 | } |
194 | ||
8dba599d | 195 | /* |
5f53d8ca JC |
196 | * Function: cmpk_handle_interrupt_status() |
197 | * | |
198 | * Overview: The function is responsible for extract the message from | |
8dba599d FS |
199 | * firmware. It will contain dedicated info in |
200 | * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc. | |
201 | * Please refer to chapter "Interrupt Status Element". | |
5f53d8ca JC |
202 | * |
203 | * Input: struct net_device *dev, | |
8dba599d | 204 | * u8* pmsg - Message Pointer of the command packet. |
5f53d8ca JC |
205 | * |
206 | * Output: NONE | |
207 | * | |
208 | * Return: NONE | |
8dba599d FS |
209 | */ |
210 | static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg) | |
5f53d8ca JC |
211 | { |
212 | cmpk_intr_sta_t rx_intr_status; /* */ | |
213 | struct r8192_priv *priv = ieee80211_priv(dev); | |
214 | ||
215 | DMESG("---> cmpk_Handle_Interrupt_Status()\n"); | |
216 | ||
5f53d8ca | 217 | /* 1. Extract TX feedback info from RFD to temp structure buffer. */ |
5f53d8ca | 218 | rx_intr_status.length = pmsg[1]; |
8dba599d | 219 | if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) { |
5f53d8ca JC |
220 | DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n"); |
221 | return; | |
222 | } | |
8dba599d FS |
223 | /* Statistics of beacon for ad-hoc mode. */ |
224 | if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) { | |
5f53d8ca JC |
225 | //2 maybe need endian transform? |
226 | rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4)); | |
227 | //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4))); | |
228 | ||
229 | DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status); | |
230 | ||
8dba599d | 231 | if (rx_intr_status.interrupt_status & ISR_TxBcnOk) { |
5f53d8ca JC |
232 | priv->ieee80211->bibsscoordinator = true; |
233 | priv->stats.txbeaconokint++; | |
8dba599d | 234 | } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) { |
5f53d8ca JC |
235 | priv->ieee80211->bibsscoordinator = false; |
236 | priv->stats.txbeaconerr++; | |
237 | } | |
238 | ||
239 | if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr) | |
5f53d8ca | 240 | cmdpkt_beacontimerinterrupt_819xusb(dev); |
5f53d8ca | 241 | } |
8dba599d | 242 | /* Other informations in interrupt status we need? */ |
5f53d8ca | 243 | DMESG("<---- cmpk_handle_interrupt_status()\n"); |
8dba599d | 244 | } |
5f53d8ca | 245 | |
8dba599d | 246 | /* |
5f53d8ca JC |
247 | * Function: cmpk_handle_query_config_rx() |
248 | * | |
249 | * Overview: The function is responsible for extract the message from | |
250 | * firmware. It will contain dedicated info in | |
8dba599d FS |
251 | * ws-06-0063-rtl8190-command-packet-specification |
252 | * Please refer to chapter "Beacon State Element". | |
5f53d8ca JC |
253 | * |
254 | * Input: u8 * pmsg - Message Pointer of the command packet. | |
255 | * | |
256 | * Output: NONE | |
257 | * | |
258 | * Return: NONE | |
259 | * | |
8dba599d FS |
260 | */ |
261 | static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg) | |
5f53d8ca | 262 | { |
8dba599d FS |
263 | cmpk_query_cfg_t rx_query_cfg; |
264 | /* | |
265 | * Extract TX feedback info from RFD to temp structure buffer. | |
266 | */ | |
267 | rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31; | |
268 | rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5; | |
269 | rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3; | |
270 | rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0; | |
271 | rx_query_cfg.cfg_offset = pmsg[7]; | |
272 | rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) | | |
273 | (pmsg[10] << 8) | (pmsg[11] << 0); | |
274 | rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) | | |
275 | (pmsg[14] << 8) | (pmsg[15] << 0); | |
276 | } | |
5f53d8ca | 277 | |
8dba599d | 278 | /* |
5f53d8ca JC |
279 | * Function: cmpk_count_tx_status() |
280 | * | |
8dba599d | 281 | * Overview: Count aggregated tx status from firmware of one type rx command |
5f53d8ca JC |
282 | * packet element id = RX_TX_STATUS. |
283 | * | |
284 | * Input: NONE | |
285 | * | |
286 | * Output: NONE | |
287 | * | |
288 | * Return: NONE | |
8dba599d FS |
289 | */ |
290 | static void cmpk_count_tx_status(struct net_device *dev, | |
291 | cmpk_tx_status_t *pstx_status) | |
5f53d8ca JC |
292 | { |
293 | struct r8192_priv *priv = ieee80211_priv(dev); | |
294 | ||
295 | #ifdef ENABLE_PS | |
296 | ||
297 | RT_RF_POWER_STATE rtstate; | |
298 | ||
299 | pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); | |
300 | ||
8dba599d FS |
301 | /* |
302 | * When RF is off, we should not count the packet for hw/sw synchronize | |
303 | * reason, ie. there may be a duration while sw switch is changed and hw | |
304 | * switch is being changed. | |
305 | */ | |
5f53d8ca | 306 | if (rtState == eRfOff) |
5f53d8ca | 307 | return; |
5f53d8ca JC |
308 | #endif |
309 | ||
310 | priv->stats.txfeedbackok += pstx_status->txok; | |
311 | priv->stats.txoktotal += pstx_status->txok; | |
312 | ||
313 | priv->stats.txfeedbackfail += pstx_status->txfail; | |
314 | priv->stats.txerrtotal += pstx_status->txfail; | |
315 | ||
8dba599d | 316 | priv->stats.txretrycount += pstx_status->txretry; |
5f53d8ca JC |
317 | priv->stats.txfeedbackretry += pstx_status->txretry; |
318 | ||
8dba599d FS |
319 | priv->stats.txmulticast += pstx_status->txmcok; |
320 | priv->stats.txbroadcast += pstx_status->txbcok; | |
5f53d8ca JC |
321 | priv->stats.txunicast += pstx_status->txucok; |
322 | ||
323 | priv->stats.txerrmulticast += pstx_status->txmcfail; | |
324 | priv->stats.txerrbroadcast += pstx_status->txbcfail; | |
325 | priv->stats.txerrunicast += pstx_status->txucfail; | |
326 | ||
327 | priv->stats.txbytesmulticast += pstx_status->txmclength; | |
328 | priv->stats.txbytesbroadcast += pstx_status->txbclength; | |
8dba599d | 329 | priv->stats.txbytesunicast += pstx_status->txuclength; |
5f53d8ca | 330 | |
8dba599d FS |
331 | priv->stats.last_packet_rate = pstx_status->rate; |
332 | } | |
5f53d8ca | 333 | |
8dba599d | 334 | /* |
5f53d8ca JC |
335 | * Function: cmpk_handle_tx_status() |
336 | * | |
337 | * Overview: Firmware add a new tx feedback status to reduce rx command | |
338 | * packet buffer operation load. | |
339 | * | |
340 | * Input: NONE | |
341 | * | |
342 | * Output: NONE | |
343 | * | |
344 | * Return: NONE | |
8dba599d | 345 | */ |
5f53d8ca | 346 | static void |
8dba599d | 347 | cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg) |
5f53d8ca | 348 | { |
8dba599d | 349 | cmpk_tx_status_t rx_tx_sts; |
5f53d8ca | 350 | |
8dba599d | 351 | memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t)); |
5f53d8ca JC |
352 | /* 2. Use tx feedback info to count TX statistics. */ |
353 | cmpk_count_tx_status(dev, &rx_tx_sts); | |
8dba599d | 354 | } |
5f53d8ca | 355 | |
8dba599d | 356 | /* |
5f53d8ca JC |
357 | * Function: cmpk_handle_tx_rate_history() |
358 | * | |
359 | * Overview: Firmware add a new tx rate history | |
360 | * | |
361 | * Input: NONE | |
362 | * | |
363 | * Output: NONE | |
364 | * | |
365 | * Return: NONE | |
8dba599d FS |
366 | */ |
367 | static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg) | |
5f53d8ca JC |
368 | { |
369 | cmpk_tx_rahis_t *ptxrate; | |
8dba599d FS |
370 | u8 i, j; |
371 | u16 length = sizeof(cmpk_tx_rahis_t); | |
372 | u32 *ptemp; | |
5f53d8ca JC |
373 | struct r8192_priv *priv = ieee80211_priv(dev); |
374 | ||
5f53d8ca | 375 | #ifdef ENABLE_PS |
8dba599d FS |
376 | pAdapter->HalFunc.GetHwRegHandler(pAdapter, |
377 | HW_VAR_RF_STATE, | |
378 | (pu1Byte)(&rtState)); | |
379 | /* | |
380 | * When RF is off, we should not count the packet for hw/sw synchronize | |
381 | * reason, ie. there may be a duration while sw switch is changed and hw | |
382 | * switch is being changed. | |
383 | */ | |
5f53d8ca | 384 | if (rtState == eRfOff) |
5f53d8ca | 385 | return; |
5f53d8ca | 386 | #endif |
5f53d8ca JC |
387 | ptemp = (u32 *)pmsg; |
388 | ||
8dba599d FS |
389 | /* |
390 | * Do endian transfer to word alignment(16 bits) for windows system. | |
391 | * You must do different endian transfer for linux and MAC OS | |
392 | */ | |
393 | for (i = 0; i < (length/4); i++) { | |
394 | u16 temp1, temp2; | |
395 | temp1 = ptemp[i] & 0x0000FFFF; | |
396 | temp2 = ptemp[i] >> 16; | |
397 | ptemp[i] = (temp1 << 16) | temp2; | |
5f53d8ca JC |
398 | } |
399 | ||
400 | ptxrate = (cmpk_tx_rahis_t *)pmsg; | |
401 | ||
8dba599d | 402 | if (ptxrate == NULL) |
5f53d8ca | 403 | return; |
5f53d8ca | 404 | |
8dba599d FS |
405 | for (i = 0; i < 16; i++) { |
406 | /* Collect CCK rate packet num */ | |
5f53d8ca JC |
407 | if (i < 4) |
408 | priv->stats.txrate.cck[i] += ptxrate->cck[i]; | |
8dba599d FS |
409 | /* Collect OFDM rate packet num */ |
410 | if (i < 8) | |
5f53d8ca | 411 | priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i]; |
5f53d8ca JC |
412 | for (j = 0; j < 4; j++) |
413 | priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i]; | |
414 | } | |
415 | ||
8dba599d | 416 | } |
5f53d8ca | 417 | |
8dba599d | 418 | /* |
5f53d8ca JC |
419 | * Function: cmpk_message_handle_rx() |
420 | * | |
421 | * Overview: In the function, we will capture different RX command packet | |
8dba599d FS |
422 | * info. Every RX command packet element has different message |
423 | * length and meaning in content. We only support three type of RX | |
424 | * command packet now. Please refer to document | |
425 | * ws-06-0063-rtl8190-command-packet-specification. | |
5f53d8ca JC |
426 | * |
427 | * Input: NONE | |
428 | * | |
429 | * Output: NONE | |
430 | * | |
431 | * Return: NONE | |
8dba599d | 432 | */ |
5f53d8ca JC |
433 | extern u32 |
434 | cmpk_message_handle_rx( | |
435 | struct net_device *dev, | |
436 | struct ieee80211_rx_stats *pstats) | |
437 | { | |
5f53d8ca JC |
438 | struct r8192_priv *priv = ieee80211_priv(dev); |
439 | int total_length; | |
440 | u8 cmd_length, exe_cnt = 0; | |
441 | u8 element_id; | |
442 | u8 *pcmd_buff; | |
443 | ||
8dba599d FS |
444 | /* |
445 | * 0. Check input arguments. | |
446 | * If is is a command queue message or pointer is null | |
447 | */ | |
448 | if ((pstats == NULL)) | |
5f53d8ca | 449 | return 0; /* This is not a command packet. */ |
5f53d8ca JC |
450 | |
451 | /* 1. Read received command packet message length from RFD. */ | |
452 | total_length = pstats->Length; | |
453 | ||
454 | /* 2. Read virtual address from RFD. */ | |
455 | pcmd_buff = pstats->virtual_address; | |
456 | ||
457 | /* 3. Read command pakcet element id and length. */ | |
458 | element_id = pcmd_buff[0]; | |
5f53d8ca | 459 | |
8dba599d FS |
460 | /* |
461 | * 4. Check every received command packet conent according to different | |
462 | * element type. Because FW may aggregate RX command packet to minimize | |
463 | * transmit time between DRV and FW. | |
464 | */ | |
5f53d8ca | 465 | |
8dba599d FS |
466 | /* Add a counter to prevent to locked in the loop too long */ |
467 | while (total_length > 0 || exe_cnt++ > 100) { | |
468 | /* We support aggregation of different cmd in the same packet */ | |
469 | element_id = pcmd_buff[0]; | |
470 | switch (element_id) { | |
471 | case RX_TX_FEEDBACK: | |
472 | cmpk_handle_tx_feedback(dev, pcmd_buff); | |
473 | cmd_length = CMPK_RX_TX_FB_SIZE; | |
474 | break; | |
475 | case RX_INTERRUPT_STATUS: | |
476 | cmpk_handle_interrupt_status(dev, pcmd_buff); | |
477 | cmd_length = sizeof(cmpk_intr_sta_t); | |
478 | break; | |
479 | case BOTH_QUERY_CONFIG: | |
480 | cmpk_handle_query_config_rx(dev, pcmd_buff); | |
481 | cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE; | |
482 | break; | |
483 | case RX_TX_STATUS: | |
484 | cmpk_handle_tx_status(dev, pcmd_buff); | |
485 | cmd_length = CMPK_RX_TX_STS_SIZE; | |
486 | break; | |
487 | case RX_TX_PER_PKT_FEEDBACK: | |
488 | cmd_length = CMPK_RX_TX_FB_SIZE; | |
489 | break; | |
490 | case RX_TX_RATE_HISTORY: | |
491 | cmpk_handle_tx_rate_history(dev, pcmd_buff); | |
492 | cmd_length = CMPK_TX_RAHIS_SIZE; | |
493 | break; | |
494 | default: | |
495 | RT_TRACE(COMP_ERR, "(%s): unknown CMD Element\n", | |
496 | __func__); | |
497 | return 1; /* This is a command packet. */ | |
498 | } | |
5f53d8ca | 499 | priv->stats.rxcmdpkt[element_id]++; |
5f53d8ca JC |
500 | total_length -= cmd_length; |
501 | pcmd_buff += cmd_length; | |
8dba599d FS |
502 | } |
503 | return 1; /* This is a command packet. */ | |
504 | } |