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