]> Pileus Git - ~andy/linux/blob - drivers/staging/rtl8192e/r819xE_cmdpkt.c
staging: rtl8192e: Remove unused members from struct Stats
[~andy/linux] / drivers / staging / rtl8192e / r819xE_cmdpkt.c
1 /******************************************************************************
2
3      (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
4
5  Module:        r819xusb_cmdpkt.c       (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
10                                 command packet.
11
12  Function:
13
14  Export:
15
16  Abbrev:
17
18  History:
19         Data            Who             Remark
20
21         05/06/2008  amy         Create initial version porting from windows driver.
22
23 ******************************************************************************/
24 #include "r8192E.h"
25 #include "r8192E_hw.h"
26 #include "r819xE_cmdpkt.h"
27
28 /*
29  * Driver internal module can call the API to send message to
30  * firmware side. For example, you can send a debug command packet.
31  * Or you can send a request for FW to modify RLX4181 LBUS HW bank.
32  * Otherwise, you can change MAC/PHT/RF register by firmware at
33  * run time. We do not support message more than one segment now.
34  */
35 RT_STATUS cmpk_message_handle_tx(
36         struct net_device *dev,
37         u8*     code_virtual_address,
38         u32     packettype,
39         u32     buffer_len)
40 {
41
42         RT_STATUS           rt_status = RT_STATUS_SUCCESS;
43 #ifdef RTL8192U
44         return rt_status;
45 #else
46         struct r8192_priv   *priv = ieee80211_priv(dev);
47         u16                 frag_threshold;
48         u16                 frag_length = 0, frag_offset = 0;
49         rt_firmware         *pfirmware = priv->pFirmware;
50         struct sk_buff      *skb;
51         unsigned char       *seg_ptr;
52         cb_desc             *tcb_desc;
53         u8                  bLastIniPkt;
54
55         PTX_FWINFO_8190PCI      pTxFwInfo = NULL;
56         int i;
57
58         //spin_lock_irqsave(&priv->tx_lock,flags);
59         RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
60         firmware_init_param(dev);
61         //Fragmentation might be required
62         frag_threshold = pfirmware->cmdpacket_frag_thresold;
63         do {
64             if((buffer_len - frag_offset) > frag_threshold) {
65                 frag_length = frag_threshold ;
66                 bLastIniPkt = 0;
67
68             } else {
69                 frag_length =(u16)(buffer_len - frag_offset);
70                 bLastIniPkt = 1;
71
72             }
73
74             /* Allocate skb buffer to contain firmware info and tx descriptor info
75              * add 4 to avoid packet appending overflow.
76              * */
77 #ifdef RTL8192U
78             skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
79 #else
80             skb  = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
81 #endif
82             if(skb == NULL) {
83                 rt_status = RT_STATUS_FAILURE;
84                 goto Failed;
85             }
86
87             memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
88             tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
89             tcb_desc->queue_index = TXCMD_QUEUE;
90             tcb_desc->bCmdOrInit = packettype;
91             tcb_desc->bLastIniPkt = bLastIniPkt;
92             tcb_desc->pkt_size = frag_length;
93
94 #ifdef RTL8192U
95             skb_reserve(skb, USB_HWDESC_HEADER_LEN);
96 #endif
97
98             //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
99             seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
100
101             pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
102             memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
103             memset(pTxFwInfo,0x12,8);
104
105             seg_ptr +=sizeof(TX_FWINFO_8190PCI);
106
107             /*
108              * Transform from little endian to big endian
109              * and pending  zero
110              */
111             seg_ptr = skb_tail_pointer(skb);
112             for(i=0 ; i < frag_length; i+=4) {
113                 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
114                 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
115                 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
116                 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
117             }
118             skb_put(skb, i);
119             priv->ieee80211->softmac_hard_start_xmit(skb,dev);
120
121             code_virtual_address += frag_length;
122             frag_offset += frag_length;
123
124         }while(frag_offset < buffer_len);
125
126 Failed:
127         //spin_unlock_irqrestore(&priv->tx_lock,flags);
128         return rt_status;
129
130
131 #endif
132 }
133
134 static void
135 cmpk_count_txstatistic(
136         struct net_device *dev,
137         cmpk_txfb_t     *pstx_fb)
138 {
139         struct r8192_priv *priv = ieee80211_priv(dev);
140 #ifdef ENABLE_PS
141         RT_RF_POWER_STATE       rtState;
142
143         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
144
145         // When RF is off, we should not count the packet for hw/sw synchronize
146         // reason, ie. there may be a duration while sw switch is changed and hw
147         // switch is being changed. 2006.12.04, by shien chang.
148         if (rtState == eRfOff)
149         {
150                 return;
151         }
152 #endif
153
154 #ifdef TODO
155         if(pAdapter->bInHctTest)
156                 return;
157 #endif
158         /* We can not know the packet length and transmit type: broadcast or uni
159            or multicast. So the relative statistics must be collected in tx
160            feedback info. */
161         if (pstx_fb->tok)
162         {
163                 priv->stats.txoktotal++;
164
165                 /* We can not make sure broadcast/multicast or unicast mode. */
166                 if (pstx_fb->pkt_type != PACKET_MULTICAST &&
167                     pstx_fb->pkt_type != PACKET_BROADCAST) {
168                         priv->stats.txunicast++;
169                         priv->stats.txbytesunicast += pstx_fb->pkt_length;
170                 }
171         }
172 }
173
174
175
176 /*
177  * The function is responsible for extract the message inside TX
178  * feedbck message from firmware. It will contain dedicated info in
179  * ws-06-0063-rtl8190-command-packet-specification. Please
180  * refer to chapter "TX Feedback Element". We have to read 20 bytes
181  * in the command packet.
182  */
183 static void
184 cmpk_handle_tx_feedback(
185         struct net_device *dev,
186         u8      *       pmsg)
187 {
188         struct r8192_priv *priv = ieee80211_priv(dev);
189         cmpk_txfb_t             rx_tx_fb;       /* */
190
191         priv->stats.txfeedback++;
192
193         /* 0. Display received message. */
194         //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg);
195
196         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
197         /* It seems that FW use big endian(MIPS) and DRV use little endian in
198            windows OS. So we have to read the content byte by byte or transfer
199            endian type before copy the message copy. */
200 #if 0           // The TX FEEDBACK packet element address
201         //rx_tx_fb.Element_ID   = pMsg[0];
202         //rx_tx_fb.Length               = pMsg[1];
203         rx_tx_fb.TOK                    = pMsg[2]>>7;
204         rx_tx_fb.Fail_Reason    = (pMsg[2] & 0x70) >> 4;
205         rx_tx_fb.TID                    = (pMsg[2] & 0x0F);
206         rx_tx_fb.Qos_Pkt                = pMsg[3] >> 7;
207         rx_tx_fb.Bandwidth              = (pMsg[3] & 0x40) >> 6;
208         rx_tx_fb.Retry_Cnt              = pMsg[5];
209         rx_tx_fb.Pkt_ID                 = (pMsg[6] << 8) | pMsg[7];
210         rx_tx_fb.Seq_Num                = (pMsg[8] << 8) | pMsg[9];
211         rx_tx_fb.S_Rate                 = pMsg[10];
212         rx_tx_fb.F_Rate                 = pMsg[11];
213         rx_tx_fb.S_RTS_Rate     = pMsg[12];
214         rx_tx_fb.F_RTS_Rate     = pMsg[13];
215         rx_tx_fb.pkt_length     = (pMsg[14] << 8) | pMsg[15];
216 #endif
217         /* 2007/07/05 MH Use pointer to transfer structure memory. */
218         //memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T));
219         memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
220         /* 2. Use tx feedback info to count TX statistics. */
221         cmpk_count_txstatistic(dev, &rx_tx_fb);
222 #if 0
223         /* 2007/07/11 MH Assign current operate rate.  */
224         if (pAdapter->RegWirelessMode == WIRELESS_MODE_A ||
225                 pAdapter->RegWirelessMode == WIRELESS_MODE_B ||
226                 pAdapter->RegWirelessMode == WIRELESS_MODE_G)
227         {
228                 pMgntInfo->CurrentOperaRate = (rx_tx_fb.F_Rate & 0x7F);
229         }
230         else if (pAdapter->RegWirelessMode == WIRELESS_MODE_N_24G ||
231                          pAdapter->RegWirelessMode == WIRELESS_MODE_N_5G)
232         {
233                 pMgntInfo->HTCurrentOperaRate = (rx_tx_fb.F_Rate & 0x8F);
234         }
235 #endif
236         /* 2007/01/17 MH Comment previous method for TX statistic function. */
237         /* Collect info TX feedback packet to fill TCB. */
238         /* We can not know the packet length and transmit type: broadcast or uni
239            or multicast. */
240         //CountTxStatistics( pAdapter, &tcb );
241
242 }
243
244
245 /*
246  * The function is responsible for extract the message from
247  * firmware. It will contain dedicated info in
248  * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
249  * Please refer to chapter "Interrupt Status Element".
250  */
251 static  void
252 cmpk_handle_interrupt_status(
253         struct net_device *dev,
254         u8*     pmsg)
255 {
256         cmpk_intr_sta_t         rx_intr_status; /* */
257         struct r8192_priv *priv = ieee80211_priv(dev);
258
259         DMESG("---> cmpk_Handle_Interrupt_Status()\n");
260
261         /* 0. Display received message. */
262         //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
263
264         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
265         /* It seems that FW use big endian(MIPS) and DRV use little endian in
266            windows OS. So we have to read the content byte by byte or transfer
267            endian type before copy the message copy. */
268         //rx_bcn_state.Element_ID       = pMsg[0];
269         //rx_bcn_state.Length           = pMsg[1];
270         rx_intr_status.length = pmsg[1];
271         if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
272         {
273                 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
274                 return;
275         }
276
277
278         // Statistics of beacon for ad-hoc mode.
279         if(     priv->ieee80211->iw_mode == IW_MODE_ADHOC)
280         {
281                 //2 maybe need endian transform?
282                 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
283                 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
284
285                 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
286
287                 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
288                 {
289                         priv->ieee80211->bibsscoordinator = true;
290                         priv->stats.txbeaconokint++;
291                 }
292                 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
293                 {
294                         priv->ieee80211->bibsscoordinator = false;
295                         priv->stats.txbeaconerr++;
296                 }
297         }
298
299          // Other informations in interrupt status we need?
300
301
302         DMESG("<---- cmpk_handle_interrupt_status()\n");
303
304 }
305
306
307 /*
308  * The function is responsible for extract the message from
309  * firmware. It will contain dedicated info in
310  * ws-06-0063-rtl8190-command-packet-specification. Please
311  * refer to chapter "Beacon State Element".
312  */
313 static  void
314 cmpk_handle_query_config_rx(
315         struct net_device *dev,
316         u8*        pmsg)
317 {
318         cmpk_query_cfg_t        rx_query_cfg;   /* */
319
320         /* 0. Display received message. */
321         //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
322
323         /* 1. Extract TX feedback info from RFD to temp structure buffer. */
324         /* It seems that FW use big endian(MIPS) and DRV use little endian in
325            windows OS. So we have to read the content byte by byte or transfer
326            endian type before copy the message copy. */
327         //rx_query_cfg.Element_ID       = pMsg[0];
328         //rx_query_cfg.Length           = pMsg[1];
329         rx_query_cfg.cfg_action         = (pmsg[4] & 0x80000000)>>31;
330         rx_query_cfg.cfg_type           = (pmsg[4] & 0x60) >> 5;
331         rx_query_cfg.cfg_size           = (pmsg[4] & 0x18) >> 3;
332         rx_query_cfg.cfg_page           = (pmsg[6] & 0x0F) >> 0;
333         rx_query_cfg.cfg_offset                 = pmsg[7];
334         rx_query_cfg.value                      = (pmsg[8] << 24) | (pmsg[9] << 16) |
335                                                                   (pmsg[10] << 8) | (pmsg[11] << 0);
336         rx_query_cfg.mask                       = (pmsg[12] << 24) | (pmsg[13] << 16) |
337                                                                   (pmsg[14] << 8) | (pmsg[15] << 0);
338
339 }
340
341
342 /*
343  * Count aggregated tx status from firmwar of one type rx command
344  * packet element id = RX_TX_STATUS.
345  */
346 static  void    cmpk_count_tx_status(   struct net_device *dev,
347                                                                         cmpk_tx_status_t        *pstx_status)
348 {
349         struct r8192_priv *priv = ieee80211_priv(dev);
350
351 #ifdef ENABLE_PS
352
353         RT_RF_POWER_STATE       rtstate;
354
355         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
356
357         // When RF is off, we should not count the packet for hw/sw synchronize
358         // reason, ie. there may be a duration while sw switch is changed and hw
359         // switch is being changed. 2006.12.04, by shien chang.
360         if (rtState == eRfOff)
361         {
362                 return;
363         }
364 #endif
365
366         priv->stats.txfeedbackok        += pstx_status->txok;
367         priv->stats.txoktotal           += pstx_status->txok;
368
369         priv->stats.txunicast           += pstx_status->txucok;
370
371         priv->stats.txbytesunicast              += pstx_status->txuclength;
372 }
373
374
375
376 /*
377  * Firmware add a new tx feedback status to reduce rx command
378  * packet buffer operation load.
379  */
380 static  void
381 cmpk_handle_tx_status(
382         struct net_device *dev,
383         u8*        pmsg)
384 {
385         cmpk_tx_status_t        rx_tx_sts;      /* */
386
387         memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
388         /* 2. Use tx feedback info to count TX statistics. */
389         cmpk_count_tx_status(dev, &rx_tx_sts);
390
391 }
392
393
394 /* Firmware add a new tx rate history */
395 static  void
396 cmpk_handle_tx_rate_history(
397         struct net_device *dev,
398         u8*        pmsg)
399 {
400         u8                              i;
401         u16                             length = sizeof(cmpk_tx_rahis_t);
402         u32                             *ptemp;
403
404 #ifdef ENABLE_PS
405         pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
406
407         // When RF is off, we should not count the packet for hw/sw synchronize
408         // reason, ie. there may be a duration while sw switch is changed and hw
409         // switch is being changed. 2006.12.04, by shien chang.
410         if (rtState == eRfOff)
411         {
412                 return;
413         }
414 #endif
415
416         ptemp = (u32 *)pmsg;
417
418         //
419         // Do endian transfer to word alignment(16 bits) for windows system.
420         // You must do different endian transfer for linux and MAC OS
421         //
422         for (i = 0; i < (length/4); i++)
423         {
424                 u16      temp1, temp2;
425
426                 temp1 = ptemp[i]&0x0000FFFF;
427                 temp2 = ptemp[i]>>16;
428                 ptemp[i] = (temp1<<16)|temp2;
429         }
430 }
431
432
433 /*
434  * In the function, we will capture different RX command packet
435  * info. Every RX command packet element has different message
436  * length and meaning in content. We only support three type of RX
437  * command packet now. Please refer to document
438  * ws-06-0063-rtl8190-command-packet-specification.
439  */
440 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
441 {
442 //      u32                     debug_level = DBG_LOUD;
443         struct r8192_priv *priv = ieee80211_priv(dev);
444         int                     total_length;
445         u8                      cmd_length, exe_cnt = 0;
446         u8                      element_id;
447         u8                      *pcmd_buff;
448
449         RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
450
451         /* 0. Check inpt arguments. If is is a command queue message or pointer is
452               null. */
453         if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
454         {
455                 /* Print error message. */
456                 /*RT_TRACE(COMP_SEND, DebugLevel,
457                                 ("\n\r[CMPK]-->Err queue id or pointer"));*/
458                 return 0;       /* This is not a command packet. */
459         }
460
461         /* 1. Read received command packet message length from RFD. */
462         total_length = pstats->Length;
463
464         /* 2. Read virtual address from RFD. */
465         pcmd_buff = pstats->virtual_address;
466
467         /* 3. Read command pakcet element id and length. */
468         element_id = pcmd_buff[0];
469         /*RT_TRACE(COMP_SEND, DebugLevel,
470                         ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
471
472         /* 4. Check every received command packet conent according to different
473               element type. Because FW may aggregate RX command packet to minimize
474               transmit time between DRV and FW.*/
475         // Add a counter to prevent to locked in the loop too long
476         while (total_length > 0 || exe_cnt++ >100)
477         {
478                 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
479                 element_id = pcmd_buff[0];
480
481                 switch(element_id)
482                 {
483                         case RX_TX_FEEDBACK:
484
485                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
486                                 cmpk_handle_tx_feedback (dev, pcmd_buff);
487                                 cmd_length = CMPK_RX_TX_FB_SIZE;
488                                 break;
489
490                         case RX_INTERRUPT_STATUS:
491
492                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
493                                 cmpk_handle_interrupt_status(dev, pcmd_buff);
494                                 cmd_length = sizeof(cmpk_intr_sta_t);
495                                 break;
496
497                         case BOTH_QUERY_CONFIG:
498
499                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
500                                 cmpk_handle_query_config_rx(dev, pcmd_buff);
501                                 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
502                                 break;
503
504                         case RX_TX_STATUS:
505
506                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
507                                 cmpk_handle_tx_status(dev, pcmd_buff);
508                                 cmd_length = CMPK_RX_TX_STS_SIZE;
509                                 break;
510
511                         case RX_TX_PER_PKT_FEEDBACK:
512                                 // You must at lease add a switch case element here,
513                                 // Otherwise, we will jump to default case.
514                                 //DbgPrint("CCX Test\r\n");
515                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
516                                 cmd_length = CMPK_RX_TX_FB_SIZE;
517                                 break;
518
519                         case RX_TX_RATE_HISTORY:
520                                 //DbgPrint(" rx tx rate history\r\n");
521
522                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
523                                 cmpk_handle_tx_rate_history(dev, pcmd_buff);
524                                 cmd_length = CMPK_TX_RAHIS_SIZE;
525                                 break;
526
527                         default:
528
529                                 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
530                                 return 1;       /* This is a command packet. */
531                 }
532                 // 2007/01/22 MH Display received rx command packet info.
533                 //cmpk_Display_Message(cmd_length, pcmd_buff);
534
535                 // 2007/01/22 MH Add to display tx statistic.
536                 //cmpk_DisplayTxStatistic(pAdapter);
537
538                 /* 2007/03/09 MH Collect sidderent cmd element pkt num. */
539                 priv->stats.rxcmdpkt[element_id]++;
540
541                 total_length -= cmd_length;
542                 pcmd_buff    += cmd_length;
543         }       /* while (total_length > 0) */
544         return  1;      /* This is a command packet. */
545
546         RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");
547 }