blob: 5ef91374b230924dbd52be91d3be9d09ff963ea0 [file] [log] [blame]
Larry Finger0c817332010-12-08 11:12:31 -06001/******************************************************************************
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"
Larry Finger1472d3a2011-02-23 10:24:58 -060034#include "../rtl8192ce/reg.h"
35#include "../rtl8192ce/def.h"
36#include "fw_common.h"
Larry Finger0c817332010-12-08 11:12:31 -060037
38static 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
73static 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
101static 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
114static 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
130static 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));
Larry Finger0c817332010-12-08 11:12:31 -0600135 u8 *bufferPtr = (u8 *) buffer;
136
137 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
138
Larry Finger25b2bc32011-02-11 14:34:03 -0600139 if (IS_CHIP_VER_B(version)) {
Larry Finger0c817332010-12-08 11:12:31 -0600140 u32 pageNums, remainSize;
141 u32 page, offset;
142
Larry Finger25b2bc32011-02-11 14:34:03 -0600143 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
Larry Finger0c817332010-12-08 11:12:31 -0600144 _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
171static 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
218exit:
219 return err;
220}
221
222int 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;
Larry Finger25b2bc32011-02-11 14:34:03 -0600231 const struct firmware *firmware;
Larry Finger0c817332010-12-08 11:12:31 -0600232
Larry Finger25b2bc32011-02-11 14:34:03 -0600233 printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n",
234 rtlpriv->cfg->fw_name);
Larry Finger0c817332010-12-08 11:12:31 -0600235 err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
236 rtlpriv->io.dev);
237 if (err) {
Larry Finger25b2bc32011-02-11 14:34:03 -0600238 printk(KERN_ERR "rtl8192cu: Firmware loading failed\n");
Larry Finger0c817332010-12-08 11:12:31 -0600239 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}
Larry Finger1472d3a2011-02-23 10:24:58 -0600281EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600282
283static 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
297static 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);
Larry Finger7ea47242011-02-19 16:28:57 -0600319 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600320 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
321 ("H2C set in progress! Wait to set.."
322 "element_id(%d).\n", element_id));
323
Larry Finger7ea47242011-02-19 16:28:57 -0600324 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600325 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 {
Larry Finger7ea47242011-02-19 16:28:57 -0600340 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600341 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);
Larry Finger7ea47242011-02-19 16:28:57 -0600496 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600497 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
498
499 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
500}
501
502void 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
Larry Finger7ea47242011-02-19 16:28:57 -0600508 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600509 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}
Larry Finger1472d3a2011-02-23 10:24:58 -0600520EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600521
522void 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}
Larry Finger1472d3a2011-02-23 10:24:58 -0600541EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600542
543void 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}
Larry Finger1472d3a2011-02-23 10:24:58 -0600562EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600563
Larry Finger0c817332010-12-08 11:12:31 -0600564#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
571static 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
681void 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
Larry Finger25b2bc32011-02-11 14:34:03 -0600747 rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600748
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}
Larry Finger1472d3a2011-02-23 10:24:58 -0600764EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600765
766void 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}
Larry Finger1472d3a2011-02-23 10:24:58 -0600774EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);