Merge tag 'gpio-v3.13-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-2.6.git] / drivers / staging / rtl8192u / r819xU_cmdpkt.c
blob7bdcbd39a3b25a3fb8c4d7eaaf6e95ac59b64ad9
1 /******************************************************************************
3 * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
5 * Module: r819xusb_cmdpkt.c
6 * (RTL8190 TX/RX command packet handler Source C File)
8 * Note: The module is responsible for handling TX and RX command packet.
9 * 1. TX : Send set and query configuration command packet.
10 * 2. RX : Receive tx feedback, beacon state, query configuration
11 * command packet.
13 * Function:
15 * Export:
17 * Abbrev:
19 * History:
21 * Date Who Remark
22 * 05/06/2008 amy Create initial version porting from
23 * windows driver.
25 ******************************************************************************/
26 #include "r8192U.h"
27 #include "r819xU_cmdpkt.h"
29 rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
31 rt_status rtStatus = RT_STATUS_SUCCESS;
32 struct r8192_priv *priv = ieee80211_priv(dev);
33 struct sk_buff *skb;
34 cb_desc *tcb_desc;
35 unsigned char *ptr_buf;
37 /* Get TCB and local buffer from common pool.
38 (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
39 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
40 if (!skb)
41 return RT_STATUS_FAILURE;
42 memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
43 tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
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);
48 ptr_buf = skb_put(skb, DataLen);
49 memcpy(ptr_buf, pData, DataLen);
50 tcb_desc->txbuf_size = (u16)DataLen;
52 if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
53 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
54 (priv->ieee80211->queue_stop)) {
55 RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
56 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
57 } else {
58 priv->ieee80211->softmac_hard_start_xmit(skb, dev);
61 return rtStatus;
64 /*-----------------------------------------------------------------------------
65 * Function: cmpk_counttxstatistic()
67 * Overview:
69 * Input: PADAPTER pAdapter
70 * CMPK_TXFB_T *psTx_FB
72 * Output: NONE
74 * Return: NONE
76 * Revised History:
77 * When Who Remark
78 * 05/12/2008 amy Create Version 0 porting from windows code.
80 *---------------------------------------------------------------------------*/
81 static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
83 struct r8192_priv *priv = ieee80211_priv(dev);
84 #ifdef ENABLE_PS
85 RT_RF_POWER_STATE rtState;
87 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
88 (pu1Byte)(&rtState));
90 /* When RF is off, we should not count the packet for hw/sw synchronize
91 reason, ie. there may be a duration while sw switch is changed and
92 hw switch is being changed. */
93 if (rtState == eRfOff)
94 return;
95 #endif
97 #ifdef TODO
98 if (pAdapter->bInHctTest)
99 return;
100 #endif
101 /* We can not know the packet length and transmit type:
102 broadcast or uni or multicast. So the relative statistics
103 must be collected in tx feedback info. */
104 if (pstx_fb->tok) {
105 priv->stats.txfeedbackok++;
106 priv->stats.txoktotal++;
107 priv->stats.txokbytestotal += pstx_fb->pkt_length;
108 priv->stats.txokinperiod++;
110 /* We can not make sure broadcast/multicast or unicast mode. */
111 if (pstx_fb->pkt_type == PACKET_MULTICAST) {
112 priv->stats.txmulticast++;
113 priv->stats.txbytesmulticast += pstx_fb->pkt_length;
114 } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
115 priv->stats.txbroadcast++;
116 priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
117 } else {
118 priv->stats.txunicast++;
119 priv->stats.txbytesunicast += pstx_fb->pkt_length;
121 } else {
122 priv->stats.txfeedbackfail++;
123 priv->stats.txerrtotal++;
124 priv->stats.txerrbytestotal += pstx_fb->pkt_length;
126 /* We can not make sure broadcast/multicast or unicast mode. */
127 if (pstx_fb->pkt_type == PACKET_MULTICAST)
128 priv->stats.txerrmulticast++;
129 else if (pstx_fb->pkt_type == PACKET_BROADCAST)
130 priv->stats.txerrbroadcast++;
131 else
132 priv->stats.txerrunicast++;
135 priv->stats.txretrycount += pstx_fb->retry_cnt;
136 priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
142 /*-----------------------------------------------------------------------------
143 * Function: cmpk_handle_tx_feedback()
145 * Overview: The function is responsible for extract the message inside TX
146 * feedbck message from firmware. It will contain dedicated info in
147 * ws-06-0063-rtl8190-command-packet-specification.
148 * Please refer to chapter "TX Feedback Element".
149 * We have to read 20 bytes in the command packet.
151 * Input: struct net_device *dev
152 * u8 *pmsg - Msg Ptr of the command packet.
154 * Output: NONE
156 * Return: NONE
158 * Revised History:
159 * When Who Remark
160 * 05/08/2008 amy Create Version 0 porting from windows code.
162 *---------------------------------------------------------------------------*/
163 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
165 struct r8192_priv *priv = ieee80211_priv(dev);
166 cmpk_txfb_t rx_tx_fb;
168 priv->stats.txfeedback++;
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
172 windows OS. So we have to read the content byte by byte or transfer
173 endian type before copy the message copy. */
174 /* Use pointer to transfer structure memory. */
175 memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
176 /* 2. Use tx feedback info to count TX statistics. */
177 cmpk_count_txstatistic(dev, &rx_tx_fb);
178 /* Comment previous method for TX statistic function. */
179 /* Collect info TX feedback packet to fill TCB. */
180 /* We can not know the packet length and transmit type: broadcast or uni
181 or multicast. */
185 void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
187 struct r8192_priv *priv = ieee80211_priv(dev);
188 u16 tx_rate;
189 /* 87B have to S/W beacon for DTM encryption_cmn. */
190 if (priv->ieee80211->current_network.mode == IEEE_A ||
191 priv->ieee80211->current_network.mode == IEEE_N_5G ||
192 (priv->ieee80211->current_network.mode == IEEE_N_24G &&
193 (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
194 tx_rate = 60;
195 DMESG("send beacon frame tx rate is 6Mbpm\n");
196 } else {
197 tx_rate = 10;
198 DMESG("send beacon frame tx rate is 1Mbpm\n");
201 rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
209 /*-----------------------------------------------------------------------------
210 * Function: cmpk_handle_interrupt_status()
212 * Overview: The function is responsible for extract the message from
213 * firmware. It will contain dedicated info in
214 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
215 * Please refer to chapter "Interrupt Status Element".
217 * Input: struct net_device *dev
218 * u8 *pmsg - Message Pointer of the command packet.
220 * Output: NONE
222 * Return: NONE
224 * Revised History:
225 * When Who Remark
226 * 05/12/2008 amy Add this for rtl8192 porting from windows code.
228 *---------------------------------------------------------------------------*/
229 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
231 cmpk_intr_sta_t rx_intr_status; /* */
232 struct r8192_priv *priv = ieee80211_priv(dev);
234 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
236 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
237 /* It seems that FW use big endian(MIPS) and DRV use little endian in
238 windows OS. So we have to read the content byte by byte or transfer
239 endian type before copy the message copy. */
240 rx_intr_status.length = pmsg[1];
241 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
242 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
243 return;
247 /* Statistics of beacon for ad-hoc mode. */
248 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
249 /* 2 maybe need endian transform? */
250 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
252 DMESG("interrupt status = 0x%x\n",
253 rx_intr_status.interrupt_status);
255 if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
256 priv->ieee80211->bibsscoordinator = true;
257 priv->stats.txbeaconokint++;
258 } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
259 priv->ieee80211->bibsscoordinator = false;
260 priv->stats.txbeaconerr++;
263 if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
264 cmdpkt_beacontimerinterrupt_819xusb(dev);
268 /* Other informations in interrupt status we need? */
271 DMESG("<---- cmpk_handle_interrupt_status()\n");
276 /*-----------------------------------------------------------------------------
277 * Function: cmpk_handle_query_config_rx()
279 * Overview: The function is responsible for extract the message from
280 * firmware. It will contain dedicated info in
281 * ws-06-0063-rtl8190-command-packet-specification. Please
282 * refer to chapter "Beacon State Element".
284 * Input: u8 *pmsg - Message Pointer of the command packet.
286 * Output: NONE
288 * Return: NONE
290 * Revised History:
291 * When Who Remark
292 * 05/12/2008 amy Create Version 0 porting from windows code.
294 *---------------------------------------------------------------------------*/
295 static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
297 cmpk_query_cfg_t rx_query_cfg;
300 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
301 /* It seems that FW use big endian(MIPS) and DRV use little endian in
302 windows OS. So we have to read the content byte by byte or transfer
303 endian type before copy the message copy. */
304 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31;
305 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
306 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
307 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
308 rx_query_cfg.cfg_offset = pmsg[7];
309 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
310 (pmsg[10] << 8) | (pmsg[11] << 0);
311 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
312 (pmsg[14] << 8) | (pmsg[15] << 0);
317 /*-----------------------------------------------------------------------------
318 * Function: cmpk_count_tx_status()
320 * Overview: Count aggregated tx status from firmwar of one type rx command
321 * packet element id = RX_TX_STATUS.
323 * Input: NONE
325 * Output: NONE
327 * Return: NONE
329 * Revised History:
330 * When Who Remark
331 * 05/12/2008 amy Create Version 0 porting from windows code.
333 *---------------------------------------------------------------------------*/
334 static void cmpk_count_tx_status(struct net_device *dev,
335 cmpk_tx_status_t *pstx_status)
337 struct r8192_priv *priv = ieee80211_priv(dev);
339 #ifdef ENABLE_PS
341 RT_RF_POWER_STATE rtstate;
343 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
344 (pu1Byte)(&rtState));
346 /* When RF is off, we should not count the packet for hw/sw synchronize
347 reason, ie. there may be a duration while sw switch is changed and
348 hw switch is being changed. */
349 if (rtState == eRfOff)
350 return;
351 #endif
353 priv->stats.txfeedbackok += pstx_status->txok;
354 priv->stats.txoktotal += pstx_status->txok;
356 priv->stats.txfeedbackfail += pstx_status->txfail;
357 priv->stats.txerrtotal += pstx_status->txfail;
359 priv->stats.txretrycount += pstx_status->txretry;
360 priv->stats.txfeedbackretry += pstx_status->txretry;
363 priv->stats.txmulticast += pstx_status->txmcok;
364 priv->stats.txbroadcast += pstx_status->txbcok;
365 priv->stats.txunicast += pstx_status->txucok;
367 priv->stats.txerrmulticast += pstx_status->txmcfail;
368 priv->stats.txerrbroadcast += pstx_status->txbcfail;
369 priv->stats.txerrunicast += pstx_status->txucfail;
371 priv->stats.txbytesmulticast += pstx_status->txmclength;
372 priv->stats.txbytesbroadcast += pstx_status->txbclength;
373 priv->stats.txbytesunicast += pstx_status->txuclength;
375 priv->stats.last_packet_rate = pstx_status->rate;
380 /*-----------------------------------------------------------------------------
381 * Function: cmpk_handle_tx_status()
383 * Overview: Firmware add a new tx feedback status to reduce rx command
384 * packet buffer operation load.
386 * Input: NONE
388 * Output: NONE
390 * Return: NONE
392 * Revised History:
393 * When Who Remark
394 * 05/12/2008 amy Create Version 0 porting from windows code.
396 *---------------------------------------------------------------------------*/
397 static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
399 cmpk_tx_status_t rx_tx_sts;
401 memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
402 /* 2. Use tx feedback info to count TX statistics. */
403 cmpk_count_tx_status(dev, &rx_tx_sts);
408 /*-----------------------------------------------------------------------------
409 * Function: cmpk_handle_tx_rate_history()
411 * Overview: Firmware add a new tx rate history
413 * Input: NONE
415 * Output: NONE
417 * Return: NONE
419 * Revised History:
420 * When Who Remark
421 * 05/12/2008 amy Create Version 0 porting from windows code.
423 *---------------------------------------------------------------------------*/
424 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
426 cmpk_tx_rahis_t *ptxrate;
427 u8 i, j;
428 u16 length = sizeof(cmpk_tx_rahis_t);
429 u32 *ptemp;
430 struct r8192_priv *priv = ieee80211_priv(dev);
433 #ifdef ENABLE_PS
434 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
435 (pu1Byte)(&rtState));
437 /* When RF is off, we should not count the packet for hw/sw synchronize
438 reason, ie. there may be a duration while sw switch is changed and
439 hw switch is being changed. */
440 if (rtState == eRfOff)
441 return;
442 #endif
444 ptemp = (u32 *)pmsg;
446 /* Do endian transfer to word alignment(16 bits) for windows system.
447 You must do different endian transfer for linux and MAC OS */
448 for (i = 0; i < (length/4); i++) {
449 u16 temp1, temp2;
451 temp1 = ptemp[i] & 0x0000FFFF;
452 temp2 = ptemp[i] >> 16;
453 ptemp[i] = (temp1 << 16) | temp2;
456 ptxrate = (cmpk_tx_rahis_t *)pmsg;
458 if (ptxrate == NULL)
459 return;
461 for (i = 0; i < 16; i++) {
462 /* Collect CCK rate packet num */
463 if (i < 4)
464 priv->stats.txrate.cck[i] += ptxrate->cck[i];
466 /* Collect OFDM rate packet num */
467 if (i < 8)
468 priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
470 for (j = 0; j < 4; j++)
471 priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
477 /*-----------------------------------------------------------------------------
478 * Function: cmpk_message_handle_rx()
480 * Overview: In the function, we will capture different RX command packet
481 * info. Every RX command packet element has different message
482 * length and meaning in content. We only support three type of RX
483 * command packet now. Please refer to document
484 * ws-06-0063-rtl8190-command-packet-specification.
486 * Input: NONE
488 * Output: NONE
490 * Return: NONE
492 * Revised History:
493 * When Who Remark
494 * 05/06/2008 amy Create Version 0 porting from windows code.
496 *---------------------------------------------------------------------------*/
497 u32 cmpk_message_handle_rx(struct net_device *dev,
498 struct ieee80211_rx_stats *pstats)
500 int total_length;
501 u8 cmd_length, exe_cnt = 0;
502 u8 element_id;
503 u8 *pcmd_buff;
505 /* 0. Check inpt arguments. If is is a command queue message or
506 pointer is null. */
507 if (pstats == NULL)
508 return 0; /* This is not a command packet. */
510 /* 1. Read received command packet message length from RFD. */
511 total_length = pstats->Length;
513 /* 2. Read virtual address from RFD. */
514 pcmd_buff = pstats->virtual_address;
516 /* 3. Read command packet element id and length. */
517 element_id = pcmd_buff[0];
519 /* 4. Check every received command packet content according to different
520 element type. Because FW may aggregate RX command packet to
521 minimize transmit time between DRV and FW.*/
522 /* Add a counter to prevent the lock in the loop from being held too
523 long */
524 while (total_length > 0 && exe_cnt++ < 100) {
525 /* We support aggregation of different cmd in the same packet */
526 element_id = pcmd_buff[0];
528 switch (element_id) {
529 case RX_TX_FEEDBACK:
530 cmpk_handle_tx_feedback(dev, pcmd_buff);
531 cmd_length = CMPK_RX_TX_FB_SIZE;
532 break;
534 case RX_INTERRUPT_STATUS:
535 cmpk_handle_interrupt_status(dev, pcmd_buff);
536 cmd_length = sizeof(cmpk_intr_sta_t);
537 break;
539 case BOTH_QUERY_CONFIG:
540 cmpk_handle_query_config_rx(dev, pcmd_buff);
541 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
542 break;
544 case RX_TX_STATUS:
545 cmpk_handle_tx_status(dev, pcmd_buff);
546 cmd_length = CMPK_RX_TX_STS_SIZE;
547 break;
549 case RX_TX_PER_PKT_FEEDBACK:
550 /* You must at lease add a switch case element here,
551 Otherwise, we will jump to default case. */
552 cmd_length = CMPK_RX_TX_FB_SIZE;
553 break;
555 case RX_TX_RATE_HISTORY:
556 cmpk_handle_tx_rate_history(dev, pcmd_buff);
557 cmd_length = CMPK_TX_RAHIS_SIZE;
558 break;
560 default:
562 RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
563 __func__);
564 return 1; /* This is a command packet. */
567 total_length -= cmd_length;
568 pcmd_buff += cmd_length;
570 return 1; /* This is a command packet. */