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.txbytesunicast += pstx_fb->pkt_length;
176 * The function is responsible for extract the message inside TX
177 * feedbck message from firmware. It will contain dedicated info in
178 * ws-06-0063-rtl8190-command-packet-specification. Please
179 * refer to chapter "TX Feedback Element". We have to read 20 bytes
180 * in the command packet.
183 cmpk_handle_tx_feedback(
184 struct net_device *dev,
187 struct r8192_priv *priv = ieee80211_priv(dev);
188 cmpk_txfb_t rx_tx_fb; /* */
190 priv->stats.txfeedback++;
192 /* 0. Display received message. */
193 //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg);
195 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
196 /* It seems that FW use big endian(MIPS) and DRV use little endian in
197 windows OS. So we have to read the content byte by byte or transfer
198 endian type before copy the message copy. */
199 #if 0 // The TX FEEDBACK packet element address
200 //rx_tx_fb.Element_ID = pMsg[0];
201 //rx_tx_fb.Length = pMsg[1];
202 rx_tx_fb.TOK = pMsg[2]>>7;
203 rx_tx_fb.Fail_Reason = (pMsg[2] & 0x70) >> 4;
204 rx_tx_fb.TID = (pMsg[2] & 0x0F);
205 rx_tx_fb.Qos_Pkt = pMsg[3] >> 7;
206 rx_tx_fb.Bandwidth = (pMsg[3] & 0x40) >> 6;
207 rx_tx_fb.Retry_Cnt = pMsg[5];
208 rx_tx_fb.Pkt_ID = (pMsg[6] << 8) | pMsg[7];
209 rx_tx_fb.Seq_Num = (pMsg[8] << 8) | pMsg[9];
210 rx_tx_fb.S_Rate = pMsg[10];
211 rx_tx_fb.F_Rate = pMsg[11];
212 rx_tx_fb.S_RTS_Rate = pMsg[12];
213 rx_tx_fb.F_RTS_Rate = pMsg[13];
214 rx_tx_fb.pkt_length = (pMsg[14] << 8) | pMsg[15];
216 /* 2007/07/05 MH Use pointer to transfer structure memory. */
217 //memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T));
218 memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
219 /* 2. Use tx feedback info to count TX statistics. */
220 cmpk_count_txstatistic(dev, &rx_tx_fb);
222 /* 2007/07/11 MH Assign current operate rate. */
223 if (pAdapter->RegWirelessMode == WIRELESS_MODE_A ||
224 pAdapter->RegWirelessMode == WIRELESS_MODE_B ||
225 pAdapter->RegWirelessMode == WIRELESS_MODE_G)
227 pMgntInfo->CurrentOperaRate = (rx_tx_fb.F_Rate & 0x7F);
229 else if (pAdapter->RegWirelessMode == WIRELESS_MODE_N_24G ||
230 pAdapter->RegWirelessMode == WIRELESS_MODE_N_5G)
232 pMgntInfo->HTCurrentOperaRate = (rx_tx_fb.F_Rate & 0x8F);
235 /* 2007/01/17 MH Comment previous method for TX statistic function. */
236 /* Collect info TX feedback packet to fill TCB. */
237 /* We can not know the packet length and transmit type: broadcast or uni
239 //CountTxStatistics( pAdapter, &tcb );
245 * The function is responsible for extract the message from
246 * firmware. It will contain dedicated info in
247 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
248 * Please refer to chapter "Interrupt Status Element".
251 cmpk_handle_interrupt_status(
252 struct net_device *dev,
255 cmpk_intr_sta_t rx_intr_status; /* */
256 struct r8192_priv *priv = ieee80211_priv(dev);
258 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
260 /* 0. Display received message. */
261 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
263 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
264 /* It seems that FW use big endian(MIPS) and DRV use little endian in
265 windows OS. So we have to read the content byte by byte or transfer
266 endian type before copy the message copy. */
267 //rx_bcn_state.Element_ID = pMsg[0];
268 //rx_bcn_state.Length = pMsg[1];
269 rx_intr_status.length = pmsg[1];
270 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
272 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
277 // Statistics of beacon for ad-hoc mode.
278 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
280 //2 maybe need endian transform?
281 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
282 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
284 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
286 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
288 priv->ieee80211->bibsscoordinator = true;
289 priv->stats.txbeaconokint++;
291 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
293 priv->ieee80211->bibsscoordinator = false;
294 priv->stats.txbeaconerr++;
298 // Other informations in interrupt status we need?
301 DMESG("<---- cmpk_handle_interrupt_status()\n");
307 * The function is responsible for extract the message from
308 * firmware. It will contain dedicated info in
309 * ws-06-0063-rtl8190-command-packet-specification. Please
310 * refer to chapter "Beacon State Element".
313 cmpk_handle_query_config_rx(
314 struct net_device *dev,
317 cmpk_query_cfg_t rx_query_cfg; /* */
319 /* 0. Display received message. */
320 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
322 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
323 /* It seems that FW use big endian(MIPS) and DRV use little endian in
324 windows OS. So we have to read the content byte by byte or transfer
325 endian type before copy the message copy. */
326 //rx_query_cfg.Element_ID = pMsg[0];
327 //rx_query_cfg.Length = pMsg[1];
328 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
329 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
330 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
331 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
332 rx_query_cfg.cfg_offset = pmsg[7];
333 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
334 (pmsg[10] << 8) | (pmsg[11] << 0);
335 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
336 (pmsg[14] << 8) | (pmsg[15] << 0);
342 * Count aggregated tx status from firmwar of one type rx command
343 * packet element id = RX_TX_STATUS.
345 static void cmpk_count_tx_status( struct net_device *dev,
346 cmpk_tx_status_t *pstx_status)
348 struct r8192_priv *priv = ieee80211_priv(dev);
352 RT_RF_POWER_STATE rtstate;
354 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
356 // When RF is off, we should not count the packet for hw/sw synchronize
357 // reason, ie. there may be a duration while sw switch is changed and hw
358 // switch is being changed. 2006.12.04, by shien chang.
359 if (rtState == eRfOff)
365 priv->stats.txfeedbackok += pstx_status->txok;
366 priv->stats.txoktotal += pstx_status->txok;
368 priv->stats.txbytesunicast += pstx_status->txuclength;
374 * Firmware add a new tx feedback status to reduce rx command
375 * packet buffer operation load.
378 cmpk_handle_tx_status(
379 struct net_device *dev,
382 cmpk_tx_status_t rx_tx_sts; /* */
384 memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
385 /* 2. Use tx feedback info to count TX statistics. */
386 cmpk_count_tx_status(dev, &rx_tx_sts);
391 /* Firmware add a new tx rate history */
393 cmpk_handle_tx_rate_history(
394 struct net_device *dev,
398 u16 length = sizeof(cmpk_tx_rahis_t);
402 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
404 // When RF is off, we should not count the packet for hw/sw synchronize
405 // reason, ie. there may be a duration while sw switch is changed and hw
406 // switch is being changed. 2006.12.04, by shien chang.
407 if (rtState == eRfOff)
416 // Do endian transfer to word alignment(16 bits) for windows system.
417 // You must do different endian transfer for linux and MAC OS
419 for (i = 0; i < (length/4); i++)
423 temp1 = ptemp[i]&0x0000FFFF;
424 temp2 = ptemp[i]>>16;
425 ptemp[i] = (temp1<<16)|temp2;
431 * In the function, we will capture different RX command packet
432 * info. Every RX command packet element has different message
433 * length and meaning in content. We only support three type of RX
434 * command packet now. Please refer to document
435 * ws-06-0063-rtl8190-command-packet-specification.
437 u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
439 // u32 debug_level = DBG_LOUD;
441 u8 cmd_length, exe_cnt = 0;
445 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
447 /* 0. Check inpt arguments. If is is a command queue message or pointer is
449 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
451 /* Print error message. */
452 /*RT_TRACE(COMP_SEND, DebugLevel,
453 ("\n\r[CMPK]-->Err queue id or pointer"));*/
454 return 0; /* This is not a command packet. */
457 /* 1. Read received command packet message length from RFD. */
458 total_length = pstats->Length;
460 /* 2. Read virtual address from RFD. */
461 pcmd_buff = pstats->virtual_address;
463 /* 3. Read command pakcet element id and length. */
464 element_id = pcmd_buff[0];
465 /*RT_TRACE(COMP_SEND, DebugLevel,
466 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
468 /* 4. Check every received command packet conent according to different
469 element type. Because FW may aggregate RX command packet to minimize
470 transmit time between DRV and FW.*/
471 // Add a counter to prevent to locked in the loop too long
472 while (total_length > 0 || exe_cnt++ >100)
474 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
475 element_id = pcmd_buff[0];
481 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
482 cmpk_handle_tx_feedback (dev, pcmd_buff);
483 cmd_length = CMPK_RX_TX_FB_SIZE;
486 case RX_INTERRUPT_STATUS:
488 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
489 cmpk_handle_interrupt_status(dev, pcmd_buff);
490 cmd_length = sizeof(cmpk_intr_sta_t);
493 case BOTH_QUERY_CONFIG:
495 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
496 cmpk_handle_query_config_rx(dev, pcmd_buff);
497 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
502 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
503 cmpk_handle_tx_status(dev, pcmd_buff);
504 cmd_length = CMPK_RX_TX_STS_SIZE;
507 case RX_TX_PER_PKT_FEEDBACK:
508 // You must at lease add a switch case element here,
509 // Otherwise, we will jump to default case.
510 //DbgPrint("CCX Test\r\n");
511 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
512 cmd_length = CMPK_RX_TX_FB_SIZE;
515 case RX_TX_RATE_HISTORY:
516 //DbgPrint(" rx tx rate history\r\n");
518 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
519 cmpk_handle_tx_rate_history(dev, pcmd_buff);
520 cmd_length = CMPK_TX_RAHIS_SIZE;
525 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
526 return 1; /* This is a command packet. */
529 total_length -= cmd_length;
530 pcmd_buff += cmd_length;
531 } /* while (total_length > 0) */
532 return 1; /* This is a command packet. */
534 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");