ipv6: Use ERR_CAST in addrconf_dst_alloc.
[pandora-kernel.git] / drivers / net / wireless / rtlwifi / rtl8192c / fw_common.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2010  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29
30 #include <linux/firmware.h>
31 #include "../wifi.h"
32 #include "../pci.h"
33 #include "../base.h"
34 #include "../rtl8192ce/reg.h"
35 #include "../rtl8192ce/def.h"
36 #include "fw_common.h"
37
38 static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
39 {
40         struct rtl_priv *rtlpriv = rtl_priv(hw);
41         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
42
43         if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
44                 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
45                 if (enable)
46                         value32 |= MCUFWDL_EN;
47                 else
48                         value32 &= ~MCUFWDL_EN;
49                 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
50         } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
51                 u8 tmp;
52                 if (enable) {
53
54                         tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
55                         rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
56                                        tmp | 0x04);
57
58                         tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
59                         rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
60
61                         tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
62                         rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
63                 } else {
64
65                         tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
66                         rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
67
68                         rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
69                 }
70         }
71 }
72
73 static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
74                                    const u8 *buffer, u32 size)
75 {
76         struct rtl_priv *rtlpriv = rtl_priv(hw);
77         u32 blockSize = sizeof(u32);
78         u8 *bufferPtr = (u8 *) buffer;
79         u32 *pu4BytePtr = (u32 *) buffer;
80         u32 i, offset, blockCount, remainSize;
81
82         blockCount = size / blockSize;
83         remainSize = size % blockSize;
84
85         for (i = 0; i < blockCount; i++) {
86                 offset = i * blockSize;
87                 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
88                                 *(pu4BytePtr + i));
89         }
90
91         if (remainSize) {
92                 offset = blockCount * blockSize;
93                 bufferPtr += offset;
94                 for (i = 0; i < remainSize; i++) {
95                         rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
96                                                  offset + i), *(bufferPtr + i));
97                 }
98         }
99 }
100
101 static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
102                                   u32 page, const u8 *buffer, u32 size)
103 {
104         struct rtl_priv *rtlpriv = rtl_priv(hw);
105         u8 value8;
106         u8 u8page = (u8) (page & 0x07);
107
108         value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
109
110         rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
111         _rtl92c_fw_block_write(hw, buffer, size);
112 }
113
114 static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
115 {
116         u32 fwlen = *pfwlen;
117         u8 remain = (u8) (fwlen % 4);
118
119         remain = (remain == 0) ? 0 : (4 - remain);
120
121         while (remain > 0) {
122                 pfwbuf[fwlen] = 0;
123                 fwlen++;
124                 remain--;
125         }
126
127         *pfwlen = fwlen;
128 }
129
130 static void _rtl92c_write_fw(struct ieee80211_hw *hw,
131                              enum version_8192c version, u8 *buffer, u32 size)
132 {
133         struct rtl_priv *rtlpriv = rtl_priv(hw);
134         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
135         u8 *bufferPtr = (u8 *) buffer;
136
137         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
138
139         if (IS_CHIP_VER_B(version)) {
140                 u32 pageNums, remainSize;
141                 u32 page, offset;
142
143                 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
144                         _rtl92c_fill_dummy(bufferPtr, &size);
145
146                 pageNums = size / FW_8192C_PAGE_SIZE;
147                 remainSize = size % FW_8192C_PAGE_SIZE;
148
149                 if (pageNums > 4) {
150                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
151                                  ("Page numbers should not greater then 4\n"));
152                 }
153
154                 for (page = 0; page < pageNums; page++) {
155                         offset = page * FW_8192C_PAGE_SIZE;
156                         _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
157                                               FW_8192C_PAGE_SIZE);
158                 }
159
160                 if (remainSize) {
161                         offset = pageNums * FW_8192C_PAGE_SIZE;
162                         page = pageNums;
163                         _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
164                                               remainSize);
165                 }
166         } else {
167                 _rtl92c_fw_block_write(hw, buffer, size);
168         }
169 }
170
171 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
172 {
173         struct rtl_priv *rtlpriv = rtl_priv(hw);
174         int err = -EIO;
175         u32 counter = 0;
176         u32 value32;
177
178         do {
179                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
180         } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
181                  (!(value32 & FWDL_ChkSum_rpt)));
182
183         if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
184                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
185                          ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
186                           value32));
187                 goto exit;
188         }
189
190         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
191                  ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
192
193         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
194         value32 |= MCUFWDL_RDY;
195         value32 &= ~WINTINI_RDY;
196         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
197
198         counter = 0;
199
200         do {
201                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
202                 if (value32 & WINTINI_RDY) {
203                         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
204                                  ("Polling FW ready success!!"
205                                  " REG_MCUFWDL:0x%08x .\n",
206                                  value32));
207                         err = 0;
208                         goto exit;
209                 }
210
211                 mdelay(FW_8192C_POLLING_DELAY);
212
213         } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
214
215         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
216                  ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
217
218 exit:
219         return err;
220 }
221
222 int rtl92c_download_fw(struct ieee80211_hw *hw)
223 {
224         struct rtl_priv *rtlpriv = rtl_priv(hw);
225         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
226         struct rtl92c_firmware_header *pfwheader;
227         u8 *pfwdata;
228         u32 fwsize;
229         int err;
230         enum version_8192c version = rtlhal->version;
231         const struct firmware *firmware;
232
233         printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n",
234                rtlpriv->cfg->fw_name);
235         err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
236                                rtlpriv->io.dev);
237         if (err) {
238                 printk(KERN_ERR "rtl8192cu: Firmware loading failed\n");
239                 return 1;
240         }
241
242         if (firmware->size > 0x4000) {
243                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
244                          ("Firmware is too big!\n"));
245                 release_firmware(firmware);
246                 return 1;
247         }
248
249         memcpy(rtlhal->pfirmware, firmware->data, firmware->size);
250         fwsize = firmware->size;
251         release_firmware(firmware);
252
253         pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
254         pfwdata = (u8 *) rtlhal->pfirmware;
255
256         if (IS_FW_HEADER_EXIST(pfwheader)) {
257                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
258                          ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
259                           pfwheader->version, pfwheader->signature,
260                           (uint)sizeof(struct rtl92c_firmware_header)));
261
262                 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
263                 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
264         }
265
266         _rtl92c_enable_fw_download(hw, true);
267         _rtl92c_write_fw(hw, version, pfwdata, fwsize);
268         _rtl92c_enable_fw_download(hw, false);
269
270         err = _rtl92c_fw_free_to_go(hw);
271         if (err) {
272                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
273                          ("Firmware is not ready to run!\n"));
274         } else {
275                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
276                          ("Firmware is ready to run!\n"));
277         }
278
279         return 0;
280 }
281 EXPORT_SYMBOL(rtl92c_download_fw);
282
283 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
284 {
285         struct rtl_priv *rtlpriv = rtl_priv(hw);
286         u8 val_hmetfr, val_mcutst_1;
287         bool result = false;
288
289         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
290         val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
291
292         if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
293                 result = true;
294         return result;
295 }
296
297 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
298                               u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
299 {
300         struct rtl_priv *rtlpriv = rtl_priv(hw);
301         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
302         u8 boxnum;
303         u16 box_reg, box_extreg;
304         u8 u1b_tmp;
305         bool isfw_read = false;
306         u8 buf_index;
307         bool bwrite_sucess = false;
308         u8 wait_h2c_limmit = 100;
309         u8 wait_writeh2c_limmit = 100;
310         u8 boxcontent[4], boxextcontent[2];
311         u32 h2c_waitcounter = 0;
312         unsigned long flag;
313         u8 idx;
314
315         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
316
317         while (true) {
318                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
319                 if (rtlhal->h2c_setinprogress) {
320                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
321                                  ("H2C set in progress! Wait to set.."
322                                   "element_id(%d).\n", element_id));
323
324                         while (rtlhal->h2c_setinprogress) {
325                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
326                                                        flag);
327                                 h2c_waitcounter++;
328                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
329                                          ("Wait 100 us (%d times)...\n",
330                                           h2c_waitcounter));
331                                 udelay(100);
332
333                                 if (h2c_waitcounter > 1000)
334                                         return;
335                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
336                                                   flag);
337                         }
338                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
339                 } else {
340                         rtlhal->h2c_setinprogress = true;
341                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
342                         break;
343                 }
344         }
345
346         while (!bwrite_sucess) {
347                 wait_writeh2c_limmit--;
348                 if (wait_writeh2c_limmit == 0) {
349                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
350                                  ("Write H2C fail because no trigger "
351                                   "for FW INT!\n"));
352                         break;
353                 }
354
355                 boxnum = rtlhal->last_hmeboxnum;
356                 switch (boxnum) {
357                 case 0:
358                         box_reg = REG_HMEBOX_0;
359                         box_extreg = REG_HMEBOX_EXT_0;
360                         break;
361                 case 1:
362                         box_reg = REG_HMEBOX_1;
363                         box_extreg = REG_HMEBOX_EXT_1;
364                         break;
365                 case 2:
366                         box_reg = REG_HMEBOX_2;
367                         box_extreg = REG_HMEBOX_EXT_2;
368                         break;
369                 case 3:
370                         box_reg = REG_HMEBOX_3;
371                         box_extreg = REG_HMEBOX_EXT_3;
372                         break;
373                 default:
374                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
375                                  ("switch case not process\n"));
376                         break;
377                 }
378
379                 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
380                 while (!isfw_read) {
381
382                         wait_h2c_limmit--;
383                         if (wait_h2c_limmit == 0) {
384                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
385                                          ("Wating too long for FW read "
386                                           "clear HMEBox(%d)!\n", boxnum));
387                                 break;
388                         }
389
390                         udelay(10);
391
392                         isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
393                         u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
394                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
395                                  ("Wating for FW read clear HMEBox(%d)!!! "
396                                   "0x1BF = %2x\n", boxnum, u1b_tmp));
397                 }
398
399                 if (!isfw_read) {
400                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
401                                  ("Write H2C register BOX[%d] fail!!!!! "
402                                   "Fw do not read.\n", boxnum));
403                         break;
404                 }
405
406                 memset(boxcontent, 0, sizeof(boxcontent));
407                 memset(boxextcontent, 0, sizeof(boxextcontent));
408                 boxcontent[0] = element_id;
409                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
410                          ("Write element_id box_reg(%4x) = %2x\n",
411                           box_reg, element_id));
412
413                 switch (cmd_len) {
414                 case 1:
415                         boxcontent[0] &= ~(BIT(7));
416                         memcpy((u8 *) (boxcontent) + 1,
417                                p_cmdbuffer + buf_index, 1);
418
419                         for (idx = 0; idx < 4; idx++) {
420                                 rtl_write_byte(rtlpriv, box_reg + idx,
421                                                boxcontent[idx]);
422                         }
423                         break;
424                 case 2:
425                         boxcontent[0] &= ~(BIT(7));
426                         memcpy((u8 *) (boxcontent) + 1,
427                                p_cmdbuffer + buf_index, 2);
428
429                         for (idx = 0; idx < 4; idx++) {
430                                 rtl_write_byte(rtlpriv, box_reg + idx,
431                                                boxcontent[idx]);
432                         }
433                         break;
434                 case 3:
435                         boxcontent[0] &= ~(BIT(7));
436                         memcpy((u8 *) (boxcontent) + 1,
437                                p_cmdbuffer + buf_index, 3);
438
439                         for (idx = 0; idx < 4; idx++) {
440                                 rtl_write_byte(rtlpriv, box_reg + idx,
441                                                boxcontent[idx]);
442                         }
443                         break;
444                 case 4:
445                         boxcontent[0] |= (BIT(7));
446                         memcpy((u8 *) (boxextcontent),
447                                p_cmdbuffer + buf_index, 2);
448                         memcpy((u8 *) (boxcontent) + 1,
449                                p_cmdbuffer + buf_index + 2, 2);
450
451                         for (idx = 0; idx < 2; idx++) {
452                                 rtl_write_byte(rtlpriv, box_extreg + idx,
453                                                boxextcontent[idx]);
454                         }
455
456                         for (idx = 0; idx < 4; idx++) {
457                                 rtl_write_byte(rtlpriv, box_reg + idx,
458                                                boxcontent[idx]);
459                         }
460                         break;
461                 case 5:
462                         boxcontent[0] |= (BIT(7));
463                         memcpy((u8 *) (boxextcontent),
464                                p_cmdbuffer + buf_index, 2);
465                         memcpy((u8 *) (boxcontent) + 1,
466                                p_cmdbuffer + buf_index + 2, 3);
467
468                         for (idx = 0; idx < 2; idx++) {
469                                 rtl_write_byte(rtlpriv, box_extreg + idx,
470                                                boxextcontent[idx]);
471                         }
472
473                         for (idx = 0; idx < 4; idx++) {
474                                 rtl_write_byte(rtlpriv, box_reg + idx,
475                                                boxcontent[idx]);
476                         }
477                         break;
478                 default:
479                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
480                                  ("switch case not process\n"));
481                         break;
482                 }
483
484                 bwrite_sucess = true;
485
486                 rtlhal->last_hmeboxnum = boxnum + 1;
487                 if (rtlhal->last_hmeboxnum == 4)
488                         rtlhal->last_hmeboxnum = 0;
489
490                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
491                          ("pHalData->last_hmeboxnum  = %d\n",
492                           rtlhal->last_hmeboxnum));
493         }
494
495         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
496         rtlhal->h2c_setinprogress = false;
497         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
498
499         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
500 }
501
502 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
503                          u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
504 {
505         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
506         u32 tmp_cmdbuf[2];
507
508         if (rtlhal->fw_ready == false) {
509                 RT_ASSERT(false, ("return H2C cmd because of Fw "
510                                   "download fail!!!\n"));
511                 return;
512         }
513
514         memset(tmp_cmdbuf, 0, 8);
515         memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
516         _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
517
518         return;
519 }
520 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
521
522 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
523 {
524         u8 u1b_tmp;
525         u8 delay = 100;
526         struct rtl_priv *rtlpriv = rtl_priv(hw);
527
528         rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
529         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
530
531         while (u1b_tmp & BIT(2)) {
532                 delay--;
533                 if (delay == 0) {
534                         RT_ASSERT(false, ("8051 reset fail.\n"));
535                         break;
536                 }
537                 udelay(50);
538                 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
539         }
540 }
541 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
542
543 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
544 {
545         struct rtl_priv *rtlpriv = rtl_priv(hw);
546         u8 u1_h2c_set_pwrmode[3] = {0};
547         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
548
549         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
550
551         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
552         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
553         SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
554                                               ppsc->reg_max_lps_awakeintvl);
555
556         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
557                       "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
558                       u1_h2c_set_pwrmode, 3);
559         rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
560
561 }
562 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
563
564 #define BEACON_PG               0 /*->1*/
565 #define PSPOLL_PG               2
566 #define NULL_PG                 3
567 #define PROBERSP_PG             4 /*->5*/
568
569 #define TOTAL_RESERVED_PKT_LEN  768
570
571 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
572         /* page 0 beacon */
573         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
574         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
575         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
576         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
578         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
579         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
580         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
581         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
582         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
583         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
587         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589
590         /* page 1 beacon */
591         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
604         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607
608         /* page 2  ps-poll */
609         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
610         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
611         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
622         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
623         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625
626         /* page 3  null */
627         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
628         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
629         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
630         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
640         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
641         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643
644         /* page 4  probe_resp */
645         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
646         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
647         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
648         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
649         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
650         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
651         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
652         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
653         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
654         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
655         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
656         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
659         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
661
662         /* page 5  probe_resp */
663         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 };
680
681 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
682 {
683         struct rtl_priv *rtlpriv = rtl_priv(hw);
684         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
685         struct sk_buff *skb = NULL;
686
687         u32 totalpacketlen;
688         bool rtstatus;
689         u8 u1RsvdPageLoc[3] = {0};
690         bool b_dlok = false;
691
692         u8 *beacon;
693         u8 *p_pspoll;
694         u8 *nullfunc;
695         u8 *p_probersp;
696         /*---------------------------------------------------------
697                                 (1) beacon
698         ---------------------------------------------------------*/
699         beacon = &reserved_page_packet[BEACON_PG * 128];
700         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
701         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
702
703         /*-------------------------------------------------------
704                                 (2) ps-poll
705         --------------------------------------------------------*/
706         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
707         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
708         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
709         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
710
711         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
712
713         /*--------------------------------------------------------
714                                 (3) null data
715         ---------------------------------------------------------*/
716         nullfunc = &reserved_page_packet[NULL_PG * 128];
717         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
718         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
719         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
720
721         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
722
723         /*---------------------------------------------------------
724                                 (4) probe response
725         ----------------------------------------------------------*/
726         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
727         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
728         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
729         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
730
731         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
732
733         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
734
735         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
736                       "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
737                       &reserved_page_packet[0], totalpacketlen);
738         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
739                       "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
740                       u1RsvdPageLoc, 3);
741
742
743         skb = dev_alloc_skb(totalpacketlen);
744         memcpy((u8 *) skb_put(skb, totalpacketlen),
745                &reserved_page_packet, totalpacketlen);
746
747         rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb);
748
749         if (rtstatus)
750                 b_dlok = true;
751
752         if (b_dlok) {
753                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
754                          ("Set RSVD page location to Fw.\n"));
755                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
756                                 "H2C_RSVDPAGE:\n",
757                                 u1RsvdPageLoc, 3);
758                 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
759                                     sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
760         } else
761                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
762                          ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
763 }
764 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
765
766 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
767 {
768         u8 u1_joinbssrpt_parm[1] = {0};
769
770         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
771
772         rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
773 }
774 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);