1 /******************************************************************************
3 (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
5 Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File)
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
21 05/06/2008 amy Create initial version porting from windows driver.
23 ******************************************************************************/
25 #include "r8192E_hw.h"
26 #include "r819xE_cmdpkt.h"
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.
35 RT_STATUS cmpk_message_handle_tx(
36 struct net_device *dev,
37 u8* code_virtual_address,
42 RT_STATUS rt_status = RT_STATUS_SUCCESS;
46 struct r8192_priv *priv = ieee80211_priv(dev);
48 u16 frag_length = 0, frag_offset = 0;
49 rt_firmware *pfirmware = priv->pFirmware;
51 unsigned char *seg_ptr;
55 PTX_FWINFO_8190PCI pTxFwInfo = NULL;
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;
64 if((buffer_len - frag_offset) > frag_threshold) {
65 frag_length = frag_threshold ;
69 frag_length =(u16)(buffer_len - frag_offset);
74 /* Allocate skb buffer to contain firmware info and tx descriptor info
75 * add 4 to avoid packet appending overflow.
78 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
80 skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
83 rt_status = RT_STATUS_FAILURE;
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;
95 skb_reserve(skb, USB_HWDESC_HEADER_LEN);
98 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
99 seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
101 pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
102 memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
103 memset(pTxFwInfo,0x12,8);
105 seg_ptr +=sizeof(TX_FWINFO_8190PCI);
108 * Transform from little endian to big endian
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;
119 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
121 code_virtual_address += frag_length;
122 frag_offset += frag_length;
124 }while(frag_offset < buffer_len);
127 //spin_unlock_irqrestore(&priv->tx_lock,flags);
135 cmpk_count_txstatistic(
136 struct net_device *dev,
137 cmpk_txfb_t *pstx_fb)
139 struct r8192_priv *priv = ieee80211_priv(dev);
141 RT_RF_POWER_STATE rtState;
143 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
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)
155 if(pAdapter->bInHctTest)
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
163 priv->stats.txoktotal++;
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;
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.
184 cmpk_handle_tx_feedback(
185 struct net_device *dev,
188 struct r8192_priv *priv = ieee80211_priv(dev);
189 cmpk_txfb_t rx_tx_fb; /* */
191 priv->stats.txfeedback++;
193 /* 0. Display received message. */
194 //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg);
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];
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);
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)
228 pMgntInfo->CurrentOperaRate = (rx_tx_fb.F_Rate & 0x7F);
230 else if (pAdapter->RegWirelessMode == WIRELESS_MODE_N_24G ||
231 pAdapter->RegWirelessMode == WIRELESS_MODE_N_5G)
233 pMgntInfo->HTCurrentOperaRate = (rx_tx_fb.F_Rate & 0x8F);
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
240 //CountTxStatistics( pAdapter, &tcb );
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".
252 cmpk_handle_interrupt_status(
253 struct net_device *dev,
256 cmpk_intr_sta_t rx_intr_status; /* */
257 struct r8192_priv *priv = ieee80211_priv(dev);
259 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
261 /* 0. Display received message. */
262 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
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))
273 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
278 // Statistics of beacon for ad-hoc mode.
279 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
281 //2 maybe need endian transform?
282 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
283 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
285 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
287 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
289 priv->ieee80211->bibsscoordinator = true;
290 priv->stats.txbeaconokint++;
292 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
294 priv->ieee80211->bibsscoordinator = false;
295 priv->stats.txbeaconerr++;
299 // Other informations in interrupt status we need?
302 DMESG("<---- cmpk_handle_interrupt_status()\n");
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".
314 cmpk_handle_query_config_rx(
315 struct net_device *dev,
318 cmpk_query_cfg_t rx_query_cfg; /* */
320 /* 0. Display received message. */
321 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
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);
343 * Count aggregated tx status from firmwar of one type rx command
344 * packet element id = RX_TX_STATUS.
346 static void cmpk_count_tx_status( struct net_device *dev,
347 cmpk_tx_status_t *pstx_status)
349 struct r8192_priv *priv = ieee80211_priv(dev);
353 RT_RF_POWER_STATE rtstate;
355 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
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)
366 priv->stats.txfeedbackok += pstx_status->txok;
367 priv->stats.txoktotal += pstx_status->txok;
369 priv->stats.txunicast += pstx_status->txucok;
371 priv->stats.txbytesunicast += pstx_status->txuclength;
377 * Firmware add a new tx feedback status to reduce rx command
378 * packet buffer operation load.
381 cmpk_handle_tx_status(
382 struct net_device *dev,
385 cmpk_tx_status_t rx_tx_sts; /* */
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);
394 /* Firmware add a new tx rate history */
396 cmpk_handle_tx_rate_history(
397 struct net_device *dev,
401 u16 length = sizeof(cmpk_tx_rahis_t);
405 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
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)
419 // Do endian transfer to word alignment(16 bits) for windows system.
420 // You must do different endian transfer for linux and MAC OS
422 for (i = 0; i < (length/4); i++)
426 temp1 = ptemp[i]&0x0000FFFF;
427 temp2 = ptemp[i]>>16;
428 ptemp[i] = (temp1<<16)|temp2;
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.
440 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
442 // u32 debug_level = DBG_LOUD;
444 u8 cmd_length, exe_cnt = 0;
448 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
450 /* 0. Check inpt arguments. If is is a command queue message or pointer is
452 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
454 /* Print error message. */
455 /*RT_TRACE(COMP_SEND, DebugLevel,
456 ("\n\r[CMPK]-->Err queue id or pointer"));*/
457 return 0; /* This is not a command packet. */
460 /* 1. Read received command packet message length from RFD. */
461 total_length = pstats->Length;
463 /* 2. Read virtual address from RFD. */
464 pcmd_buff = pstats->virtual_address;
466 /* 3. Read command pakcet element id and length. */
467 element_id = pcmd_buff[0];
468 /*RT_TRACE(COMP_SEND, DebugLevel,
469 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
471 /* 4. Check every received command packet conent according to different
472 element type. Because FW may aggregate RX command packet to minimize
473 transmit time between DRV and FW.*/
474 // Add a counter to prevent to locked in the loop too long
475 while (total_length > 0 || exe_cnt++ >100)
477 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
478 element_id = pcmd_buff[0];
484 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
485 cmpk_handle_tx_feedback (dev, pcmd_buff);
486 cmd_length = CMPK_RX_TX_FB_SIZE;
489 case RX_INTERRUPT_STATUS:
491 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
492 cmpk_handle_interrupt_status(dev, pcmd_buff);
493 cmd_length = sizeof(cmpk_intr_sta_t);
496 case BOTH_QUERY_CONFIG:
498 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
499 cmpk_handle_query_config_rx(dev, pcmd_buff);
500 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
505 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
506 cmpk_handle_tx_status(dev, pcmd_buff);
507 cmd_length = CMPK_RX_TX_STS_SIZE;
510 case RX_TX_PER_PKT_FEEDBACK:
511 // You must at lease add a switch case element here,
512 // Otherwise, we will jump to default case.
513 //DbgPrint("CCX Test\r\n");
514 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
515 cmd_length = CMPK_RX_TX_FB_SIZE;
518 case RX_TX_RATE_HISTORY:
519 //DbgPrint(" rx tx rate history\r\n");
521 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
522 cmpk_handle_tx_rate_history(dev, pcmd_buff);
523 cmd_length = CMPK_TX_RAHIS_SIZE;
528 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
529 return 1; /* This is a command packet. */
532 total_length -= cmd_length;
533 pcmd_buff += cmd_length;
534 } /* while (total_length > 0) */
535 return 1; /* This is a command packet. */
537 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");