staging: rtl8192e: Remove RTL8192P and RTL8192U ifdefs
[deliverable/linux.git] / drivers / staging / rtl8192e / r819xE_cmdpkt.c
CommitLineData
ecdfa446
GKH
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"
b6d5e884 27
533d1ffe
MM
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 */
5e1ad18a 35RT_STATUS cmpk_message_handle_tx(
ecdfa446
GKH
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;
ecdfa446
GKH
43 struct r8192_priv *priv = ieee80211_priv(dev);
44 u16 frag_threshold;
45 u16 frag_length = 0, frag_offset = 0;
46 rt_firmware *pfirmware = priv->pFirmware;
47 struct sk_buff *skb;
48 unsigned char *seg_ptr;
49 cb_desc *tcb_desc;
50 u8 bLastIniPkt;
51
52 PTX_FWINFO_8190PCI pTxFwInfo = NULL;
53 int i;
54
55 //spin_lock_irqsave(&priv->tx_lock,flags);
56 RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
57 firmware_init_param(dev);
58 //Fragmentation might be required
59 frag_threshold = pfirmware->cmdpacket_frag_thresold;
60 do {
61 if((buffer_len - frag_offset) > frag_threshold) {
62 frag_length = frag_threshold ;
63 bLastIniPkt = 0;
64
65 } else {
66 frag_length =(u16)(buffer_len - frag_offset);
67 bLastIniPkt = 1;
68
69 }
70
71 /* Allocate skb buffer to contain firmware info and tx descriptor info
72 * add 4 to avoid packet appending overflow.
73 * */
ecdfa446 74 skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
ecdfa446
GKH
75 if(skb == NULL) {
76 rt_status = RT_STATUS_FAILURE;
77 goto Failed;
78 }
79
80 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
81 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
82 tcb_desc->queue_index = TXCMD_QUEUE;
83 tcb_desc->bCmdOrInit = packettype;
84 tcb_desc->bLastIniPkt = bLastIniPkt;
85 tcb_desc->pkt_size = frag_length;
86
ecdfa446
GKH
87 //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
88 seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
89
90 pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
91 memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
92 memset(pTxFwInfo,0x12,8);
93
94 seg_ptr +=sizeof(TX_FWINFO_8190PCI);
95
96 /*
97 * Transform from little endian to big endian
98 * and pending zero
99 */
1c7ec2e8 100 seg_ptr = skb_tail_pointer(skb);
ecdfa446
GKH
101 for(i=0 ; i < frag_length; i+=4) {
102 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
103 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
104 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
105 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
106 }
107 skb_put(skb, i);
108 priv->ieee80211->softmac_hard_start_xmit(skb,dev);
109
110 code_virtual_address += frag_length;
111 frag_offset += frag_length;
112
ecdfa446
GKH
113 }while(frag_offset < buffer_len);
114
115Failed:
116 //spin_unlock_irqrestore(&priv->tx_lock,flags);
117 return rt_status;
d5abdf72 118}
ecdfa446 119
533d1ffe 120static void
ecdfa446
GKH
121cmpk_count_txstatistic(
122 struct net_device *dev,
123 cmpk_txfb_t *pstx_fb)
124{
125 struct r8192_priv *priv = ieee80211_priv(dev);
126#ifdef ENABLE_PS
127 RT_RF_POWER_STATE rtState;
128
129 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
130
131 // When RF is off, we should not count the packet for hw/sw synchronize
132 // reason, ie. there may be a duration while sw switch is changed and hw
133 // switch is being changed. 2006.12.04, by shien chang.
134 if (rtState == eRfOff)
135 {
136 return;
137 }
138#endif
139
140#ifdef TODO
141 if(pAdapter->bInHctTest)
142 return;
143#endif
144 /* We can not know the packet length and transmit type: broadcast or uni
145 or multicast. So the relative statistics must be collected in tx
146 feedback info. */
147 if (pstx_fb->tok)
148 {
ecdfa446 149 priv->stats.txoktotal++;
ecdfa446
GKH
150
151 /* We can not make sure broadcast/multicast or unicast mode. */
8cbe7ae6
MM
152 if (pstx_fb->pkt_type != PACKET_MULTICAST &&
153 pstx_fb->pkt_type != PACKET_BROADCAST) {
ecdfa446
GKH
154 priv->stats.txbytesunicast += pstx_fb->pkt_length;
155 }
156 }
d5abdf72 157}
ecdfa446
GKH
158
159
160
533d1ffe
MM
161/*
162 * The function is responsible for extract the message inside TX
163 * feedbck message from firmware. It will contain dedicated info in
164 * ws-06-0063-rtl8190-command-packet-specification. Please
165 * refer to chapter "TX Feedback Element". We have to read 20 bytes
166 * in the command packet.
167 */
168static void
ecdfa446
GKH
169cmpk_handle_tx_feedback(
170 struct net_device *dev,
171 u8 * pmsg)
172{
173 struct r8192_priv *priv = ieee80211_priv(dev);
174 cmpk_txfb_t rx_tx_fb; /* */
175
176 priv->stats.txfeedback++;
177
ecdfa446 178 memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
679b5f67 179 /* Use tx feedback info to count TX statistics. */
ecdfa446 180 cmpk_count_txstatistic(dev, &rx_tx_fb);
d5abdf72 181}
ecdfa446 182
ecdfa446 183
533d1ffe
MM
184/*
185 * The function is responsible for extract the message from
186 * firmware. It will contain dedicated info in
187 * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
188 * Please refer to chapter "Interrupt Status Element".
189 */
ecdfa446
GKH
190static void
191cmpk_handle_interrupt_status(
192 struct net_device *dev,
193 u8* pmsg)
194{
195 cmpk_intr_sta_t rx_intr_status; /* */
196 struct r8192_priv *priv = ieee80211_priv(dev);
197
198 DMESG("---> cmpk_Handle_Interrupt_Status()\n");
199
ecdfa446
GKH
200 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
201 /* It seems that FW use big endian(MIPS) and DRV use little endian in
202 windows OS. So we have to read the content byte by byte or transfer
203 endian type before copy the message copy. */
204 //rx_bcn_state.Element_ID = pMsg[0];
205 //rx_bcn_state.Length = pMsg[1];
206 rx_intr_status.length = pmsg[1];
207 if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
208 {
209 DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
210 return;
211 }
212
213
214 // Statistics of beacon for ad-hoc mode.
215 if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
216 {
217 //2 maybe need endian transform?
218 rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
219 //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
220
221 DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
222
223 if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
224 {
225 priv->ieee80211->bibsscoordinator = true;
226 priv->stats.txbeaconokint++;
227 }
228 else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
229 {
230 priv->ieee80211->bibsscoordinator = false;
231 priv->stats.txbeaconerr++;
232 }
ecdfa446
GKH
233 }
234
235 // Other informations in interrupt status we need?
236
237
238 DMESG("<---- cmpk_handle_interrupt_status()\n");
239
d5abdf72 240}
ecdfa446
GKH
241
242
533d1ffe
MM
243/*
244 * The function is responsible for extract the message from
245 * firmware. It will contain dedicated info in
246 * ws-06-0063-rtl8190-command-packet-specification. Please
247 * refer to chapter "Beacon State Element".
248 */
ecdfa446
GKH
249static void
250cmpk_handle_query_config_rx(
251 struct net_device *dev,
252 u8* pmsg)
253{
254 cmpk_query_cfg_t rx_query_cfg; /* */
255
256 /* 0. Display received message. */
257 //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
258
259 /* 1. Extract TX feedback info from RFD to temp structure buffer. */
260 /* It seems that FW use big endian(MIPS) and DRV use little endian in
261 windows OS. So we have to read the content byte by byte or transfer
262 endian type before copy the message copy. */
263 //rx_query_cfg.Element_ID = pMsg[0];
264 //rx_query_cfg.Length = pMsg[1];
265 rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
266 rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
267 rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
268 rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
269 rx_query_cfg.cfg_offset = pmsg[7];
270 rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
271 (pmsg[10] << 8) | (pmsg[11] << 0);
272 rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
273 (pmsg[14] << 8) | (pmsg[15] << 0);
274
d5abdf72 275}
ecdfa446
GKH
276
277
533d1ffe
MM
278/*
279 * Count aggregated tx status from firmwar of one type rx command
280 * packet element id = RX_TX_STATUS.
281 */
ecdfa446
GKH
282static void cmpk_count_tx_status( struct net_device *dev,
283 cmpk_tx_status_t *pstx_status)
284{
285 struct r8192_priv *priv = ieee80211_priv(dev);
286
287#ifdef ENABLE_PS
288
289 RT_RF_POWER_STATE rtstate;
290
291 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
292
293 // When RF is off, we should not count the packet for hw/sw synchronize
294 // reason, ie. there may be a duration while sw switch is changed and hw
295 // switch is being changed. 2006.12.04, by shien chang.
296 if (rtState == eRfOff)
297 {
298 return;
299 }
300#endif
301
302 priv->stats.txfeedbackok += pstx_status->txok;
303 priv->stats.txoktotal += pstx_status->txok;
304
ecdfa446 305 priv->stats.txbytesunicast += pstx_status->txuclength;
d5abdf72 306}
ecdfa446
GKH
307
308
309
533d1ffe
MM
310/*
311 * Firmware add a new tx feedback status to reduce rx command
312 * packet buffer operation load.
313 */
ecdfa446
GKH
314static void
315cmpk_handle_tx_status(
316 struct net_device *dev,
317 u8* pmsg)
318{
319 cmpk_tx_status_t rx_tx_sts; /* */
320
321 memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
322 /* 2. Use tx feedback info to count TX statistics. */
323 cmpk_count_tx_status(dev, &rx_tx_sts);
324
d5abdf72 325}
ecdfa446
GKH
326
327
533d1ffe 328/* Firmware add a new tx rate history */
ecdfa446
GKH
329static void
330cmpk_handle_tx_rate_history(
331 struct net_device *dev,
332 u8* pmsg)
333{
8cbe7ae6 334 u8 i;
ecdfa446
GKH
335 u16 length = sizeof(cmpk_tx_rahis_t);
336 u32 *ptemp;
ecdfa446
GKH
337
338#ifdef ENABLE_PS
339 pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
340
341 // When RF is off, we should not count the packet for hw/sw synchronize
342 // reason, ie. there may be a duration while sw switch is changed and hw
343 // switch is being changed. 2006.12.04, by shien chang.
344 if (rtState == eRfOff)
345 {
346 return;
347 }
348#endif
349
350 ptemp = (u32 *)pmsg;
351
352 //
353 // Do endian transfer to word alignment(16 bits) for windows system.
354 // You must do different endian transfer for linux and MAC OS
355 //
356 for (i = 0; i < (length/4); i++)
357 {
358 u16 temp1, temp2;
359
360 temp1 = ptemp[i]&0x0000FFFF;
361 temp2 = ptemp[i]>>16;
362 ptemp[i] = (temp1<<16)|temp2;
363 }
d5abdf72 364}
ecdfa446
GKH
365
366
533d1ffe
MM
367/*
368 * In the function, we will capture different RX command packet
369 * info. Every RX command packet element has different message
370 * length and meaning in content. We only support three type of RX
371 * command packet now. Please refer to document
372 * ws-06-0063-rtl8190-command-packet-specification.
373 */
5e1ad18a 374u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats)
ecdfa446
GKH
375{
376// u32 debug_level = DBG_LOUD;
ecdfa446
GKH
377 int total_length;
378 u8 cmd_length, exe_cnt = 0;
379 u8 element_id;
380 u8 *pcmd_buff;
381
382 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
383
384 /* 0. Check inpt arguments. If is is a command queue message or pointer is
385 null. */
386 if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
387 {
388 /* Print error message. */
389 /*RT_TRACE(COMP_SEND, DebugLevel,
390 ("\n\r[CMPK]-->Err queue id or pointer"));*/
391 return 0; /* This is not a command packet. */
392 }
393
394 /* 1. Read received command packet message length from RFD. */
395 total_length = pstats->Length;
396
397 /* 2. Read virtual address from RFD. */
398 pcmd_buff = pstats->virtual_address;
399
400 /* 3. Read command pakcet element id and length. */
401 element_id = pcmd_buff[0];
402 /*RT_TRACE(COMP_SEND, DebugLevel,
403 ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
404
405 /* 4. Check every received command packet conent according to different
406 element type. Because FW may aggregate RX command packet to minimize
407 transmit time between DRV and FW.*/
408 // Add a counter to prevent to locked in the loop too long
409 while (total_length > 0 || exe_cnt++ >100)
410 {
411 /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
412 element_id = pcmd_buff[0];
413
414 switch(element_id)
415 {
416 case RX_TX_FEEDBACK:
417
418 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
419 cmpk_handle_tx_feedback (dev, pcmd_buff);
420 cmd_length = CMPK_RX_TX_FB_SIZE;
421 break;
422
423 case RX_INTERRUPT_STATUS:
424
425 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
426 cmpk_handle_interrupt_status(dev, pcmd_buff);
427 cmd_length = sizeof(cmpk_intr_sta_t);
428 break;
429
430 case BOTH_QUERY_CONFIG:
431
432 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
433 cmpk_handle_query_config_rx(dev, pcmd_buff);
434 cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
435 break;
436
437 case RX_TX_STATUS:
438
439 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
440 cmpk_handle_tx_status(dev, pcmd_buff);
441 cmd_length = CMPK_RX_TX_STS_SIZE;
442 break;
443
444 case RX_TX_PER_PKT_FEEDBACK:
445 // You must at lease add a switch case element here,
446 // Otherwise, we will jump to default case.
447 //DbgPrint("CCX Test\r\n");
448 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
449 cmd_length = CMPK_RX_TX_FB_SIZE;
450 break;
451
452 case RX_TX_RATE_HISTORY:
453 //DbgPrint(" rx tx rate history\r\n");
454
455 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
456 cmpk_handle_tx_rate_history(dev, pcmd_buff);
457 cmd_length = CMPK_TX_RAHIS_SIZE;
458 break;
459
460 default:
461
bbc9a991 462 RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
ecdfa446
GKH
463 return 1; /* This is a command packet. */
464 }
ecdfa446
GKH
465
466 total_length -= cmd_length;
467 pcmd_buff += cmd_length;
468 } /* while (total_length > 0) */
469 return 1; /* This is a command packet. */
470
471 RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");
d5abdf72 472}
This page took 0.165704 seconds and 5 git commands to generate.