blob: 50303e1adff109b6fc73676bf77b3c7632c565fa [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);
Larry Finger0c817332010-12-08 11:12:31 -0600174 u32 counter = 0;
175 u32 value32;
176
177 do {
178 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
179 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
180 (!(value32 & FWDL_ChkSum_rpt)));
181
182 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
183 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
184 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
185 value32));
Larry Finger32473282011-03-27 16:19:57 -0500186 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600187 }
188
189 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
190 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
191
192 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
193 value32 |= MCUFWDL_RDY;
194 value32 &= ~WINTINI_RDY;
195 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
196
197 counter = 0;
198
199 do {
200 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
201 if (value32 & WINTINI_RDY) {
202 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
203 ("Polling FW ready success!!"
204 " REG_MCUFWDL:0x%08x .\n",
205 value32));
Larry Finger32473282011-03-27 16:19:57 -0500206 return 0;
Larry Finger0c817332010-12-08 11:12:31 -0600207 }
208
209 mdelay(FW_8192C_POLLING_DELAY);
210
211 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
212
213 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
214 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
Larry Finger32473282011-03-27 16:19:57 -0500215 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600216}
217
218int rtl92c_download_fw(struct ieee80211_hw *hw)
219{
220 struct rtl_priv *rtlpriv = rtl_priv(hw);
221 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
222 struct rtl92c_firmware_header *pfwheader;
223 u8 *pfwdata;
224 u32 fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600225 enum version_8192c version = rtlhal->version;
226
Larry Finger32473282011-03-27 16:19:57 -0500227 printk(KERN_INFO "rtl8192c: Loading firmware file %s\n",
Larry Finger25b2bc32011-02-11 14:34:03 -0600228 rtlpriv->cfg->fw_name);
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500229 if (!rtlhal->pfirmware)
Larry Finger0c817332010-12-08 11:12:31 -0600230 return 1;
Larry Finger0c817332010-12-08 11:12:31 -0600231
232 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
233 pfwdata = (u8 *) rtlhal->pfirmware;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500234 fwsize = rtlhal->fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600235
236 if (IS_FW_HEADER_EXIST(pfwheader)) {
237 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
238 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
239 pfwheader->version, pfwheader->signature,
240 (uint)sizeof(struct rtl92c_firmware_header)));
241
242 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
243 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
244 }
245
246 _rtl92c_enable_fw_download(hw, true);
247 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
248 _rtl92c_enable_fw_download(hw, false);
249
Larry Finger32473282011-03-27 16:19:57 -0500250 if (_rtl92c_fw_free_to_go(hw)) {
Larry Finger0c817332010-12-08 11:12:31 -0600251 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
252 ("Firmware is not ready to run!\n"));
253 } else {
254 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
255 ("Firmware is ready to run!\n"));
256 }
257
258 return 0;
259}
Larry Finger1472d3a2011-02-23 10:24:58 -0600260EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600261
262static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
263{
264 struct rtl_priv *rtlpriv = rtl_priv(hw);
265 u8 val_hmetfr, val_mcutst_1;
266 bool result = false;
267
268 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
269 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
270
271 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
272 result = true;
273 return result;
274}
275
276static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
277 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
278{
279 struct rtl_priv *rtlpriv = rtl_priv(hw);
280 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
281 u8 boxnum;
Larry Finger9f219bd2011-04-13 21:00:02 -0500282 u16 box_reg = 0, box_extreg = 0;
Larry Finger0c817332010-12-08 11:12:31 -0600283 u8 u1b_tmp;
284 bool isfw_read = false;
Larry Finger0c817332010-12-08 11:12:31 -0600285 bool bwrite_sucess = false;
286 u8 wait_h2c_limmit = 100;
287 u8 wait_writeh2c_limmit = 100;
288 u8 boxcontent[4], boxextcontent[2];
289 u32 h2c_waitcounter = 0;
290 unsigned long flag;
291 u8 idx;
292
293 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
294
295 while (true) {
296 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600297 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600298 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
299 ("H2C set in progress! Wait to set.."
300 "element_id(%d).\n", element_id));
301
Larry Finger7ea47242011-02-19 16:28:57 -0600302 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600303 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
304 flag);
305 h2c_waitcounter++;
306 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
307 ("Wait 100 us (%d times)...\n",
308 h2c_waitcounter));
309 udelay(100);
310
311 if (h2c_waitcounter > 1000)
312 return;
313 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
314 flag);
315 }
316 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
317 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600318 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600319 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
320 break;
321 }
322 }
323
324 while (!bwrite_sucess) {
325 wait_writeh2c_limmit--;
326 if (wait_writeh2c_limmit == 0) {
327 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
328 ("Write H2C fail because no trigger "
329 "for FW INT!\n"));
330 break;
331 }
332
333 boxnum = rtlhal->last_hmeboxnum;
334 switch (boxnum) {
335 case 0:
336 box_reg = REG_HMEBOX_0;
337 box_extreg = REG_HMEBOX_EXT_0;
338 break;
339 case 1:
340 box_reg = REG_HMEBOX_1;
341 box_extreg = REG_HMEBOX_EXT_1;
342 break;
343 case 2:
344 box_reg = REG_HMEBOX_2;
345 box_extreg = REG_HMEBOX_EXT_2;
346 break;
347 case 3:
348 box_reg = REG_HMEBOX_3;
349 box_extreg = REG_HMEBOX_EXT_3;
350 break;
351 default:
352 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
353 ("switch case not process\n"));
354 break;
355 }
356
357 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
358 while (!isfw_read) {
359
360 wait_h2c_limmit--;
361 if (wait_h2c_limmit == 0) {
362 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
363 ("Wating too long for FW read "
364 "clear HMEBox(%d)!\n", boxnum));
365 break;
366 }
367
368 udelay(10);
369
370 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
371 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
372 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
373 ("Wating for FW read clear HMEBox(%d)!!! "
374 "0x1BF = %2x\n", boxnum, u1b_tmp));
375 }
376
377 if (!isfw_read) {
378 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
379 ("Write H2C register BOX[%d] fail!!!!! "
380 "Fw do not read.\n", boxnum));
381 break;
382 }
383
384 memset(boxcontent, 0, sizeof(boxcontent));
385 memset(boxextcontent, 0, sizeof(boxextcontent));
386 boxcontent[0] = element_id;
387 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
388 ("Write element_id box_reg(%4x) = %2x\n",
389 box_reg, element_id));
390
391 switch (cmd_len) {
392 case 1:
393 boxcontent[0] &= ~(BIT(7));
394 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500395 p_cmdbuffer, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600396
397 for (idx = 0; idx < 4; idx++) {
398 rtl_write_byte(rtlpriv, box_reg + idx,
399 boxcontent[idx]);
400 }
401 break;
402 case 2:
403 boxcontent[0] &= ~(BIT(7));
404 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500405 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600406
407 for (idx = 0; idx < 4; idx++) {
408 rtl_write_byte(rtlpriv, box_reg + idx,
409 boxcontent[idx]);
410 }
411 break;
412 case 3:
413 boxcontent[0] &= ~(BIT(7));
414 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500415 p_cmdbuffer, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600416
417 for (idx = 0; idx < 4; idx++) {
418 rtl_write_byte(rtlpriv, box_reg + idx,
419 boxcontent[idx]);
420 }
421 break;
422 case 4:
423 boxcontent[0] |= (BIT(7));
424 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500425 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600426 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500427 p_cmdbuffer + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600428
429 for (idx = 0; idx < 2; idx++) {
430 rtl_write_byte(rtlpriv, box_extreg + idx,
431 boxextcontent[idx]);
432 }
433
434 for (idx = 0; idx < 4; idx++) {
435 rtl_write_byte(rtlpriv, box_reg + idx,
436 boxcontent[idx]);
437 }
438 break;
439 case 5:
440 boxcontent[0] |= (BIT(7));
441 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500442 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600443 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500444 p_cmdbuffer + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600445
446 for (idx = 0; idx < 2; idx++) {
447 rtl_write_byte(rtlpriv, box_extreg + idx,
448 boxextcontent[idx]);
449 }
450
451 for (idx = 0; idx < 4; idx++) {
452 rtl_write_byte(rtlpriv, box_reg + idx,
453 boxcontent[idx]);
454 }
455 break;
456 default:
457 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
458 ("switch case not process\n"));
459 break;
460 }
461
462 bwrite_sucess = true;
463
464 rtlhal->last_hmeboxnum = boxnum + 1;
465 if (rtlhal->last_hmeboxnum == 4)
466 rtlhal->last_hmeboxnum = 0;
467
468 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
469 ("pHalData->last_hmeboxnum = %d\n",
470 rtlhal->last_hmeboxnum));
471 }
472
473 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600474 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600475 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
476
477 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
478}
479
480void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
481 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
482{
483 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
484 u32 tmp_cmdbuf[2];
485
Larry Finger7ea47242011-02-19 16:28:57 -0600486 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600487 RT_ASSERT(false, ("return H2C cmd because of Fw "
488 "download fail!!!\n"));
489 return;
490 }
491
492 memset(tmp_cmdbuf, 0, 8);
493 memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
494 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
495
496 return;
497}
Larry Finger1472d3a2011-02-23 10:24:58 -0600498EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600499
500void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
501{
502 u8 u1b_tmp;
503 u8 delay = 100;
504 struct rtl_priv *rtlpriv = rtl_priv(hw);
505
506 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
507 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
508
509 while (u1b_tmp & BIT(2)) {
510 delay--;
511 if (delay == 0) {
512 RT_ASSERT(false, ("8051 reset fail.\n"));
513 break;
514 }
515 udelay(50);
516 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
517 }
518}
Larry Finger1472d3a2011-02-23 10:24:58 -0600519EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600520
521void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
522{
523 struct rtl_priv *rtlpriv = rtl_priv(hw);
524 u8 u1_h2c_set_pwrmode[3] = {0};
525 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
526
527 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
528
529 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
530 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
531 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
532 ppsc->reg_max_lps_awakeintvl);
533
534 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
535 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
536 u1_h2c_set_pwrmode, 3);
537 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
538
539}
Larry Finger1472d3a2011-02-23 10:24:58 -0600540EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600541
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500542static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
543 struct sk_buff *skb)
544{
545 struct rtl_priv *rtlpriv = rtl_priv(hw);
546 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
547 struct rtl8192_tx_ring *ring;
548 struct rtl_tx_desc *pdesc;
549 u8 own;
550 unsigned long flags;
551 struct sk_buff *pskb = NULL;
552
553 ring = &rtlpci->tx_ring[BEACON_QUEUE];
554
555 pskb = __skb_dequeue(&ring->queue);
556 if (pskb)
557 kfree_skb(pskb);
558
559 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
560
561 pdesc = &ring->desc[0];
562 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
563
564 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
565
566 __skb_queue_tail(&ring->queue, skb);
567
568 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
569
570 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
571
572 return true;
573}
574
Larry Finger0c817332010-12-08 11:12:31 -0600575#define BEACON_PG 0 /*->1*/
576#define PSPOLL_PG 2
577#define NULL_PG 3
578#define PROBERSP_PG 4 /*->5*/
579
580#define TOTAL_RESERVED_PKT_LEN 768
581
582static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
583 /* page 0 beacon */
584 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
585 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
586 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
589 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
590 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
591 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
592 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
593 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
594 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
598 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600
601 /* page 1 beacon */
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618
619 /* page 2 ps-poll */
620 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
621 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
634 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636
637 /* page 3 null */
638 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
639 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
640 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
652 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654
655 /* page 4 probe_resp */
656 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
657 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
658 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
659 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
660 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
661 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
662 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
663 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
664 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
665 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
666 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
670 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672
673 /* page 5 probe_resp */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690};
691
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500692void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
Larry Finger0c817332010-12-08 11:12:31 -0600693{
694 struct rtl_priv *rtlpriv = rtl_priv(hw);
695 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
696 struct sk_buff *skb = NULL;
697
698 u32 totalpacketlen;
699 bool rtstatus;
700 u8 u1RsvdPageLoc[3] = {0};
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500701 bool dlok = false;
Larry Finger0c817332010-12-08 11:12:31 -0600702
703 u8 *beacon;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500704 u8 *pspoll;
Larry Finger0c817332010-12-08 11:12:31 -0600705 u8 *nullfunc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500706 u8 *probersp;
Larry Finger0c817332010-12-08 11:12:31 -0600707 /*---------------------------------------------------------
708 (1) beacon
709 ---------------------------------------------------------*/
710 beacon = &reserved_page_packet[BEACON_PG * 128];
711 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
712 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
713
714 /*-------------------------------------------------------
715 (2) ps-poll
716 --------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500717 pspoll = &reserved_page_packet[PSPOLL_PG * 128];
718 SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
719 SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
720 SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
Larry Finger0c817332010-12-08 11:12:31 -0600721
722 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
723
724 /*--------------------------------------------------------
725 (3) null data
726 ---------------------------------------------------------*/
727 nullfunc = &reserved_page_packet[NULL_PG * 128];
728 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
729 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
730 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
731
732 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
733
734 /*---------------------------------------------------------
735 (4) probe response
736 ----------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500737 probersp = &reserved_page_packet[PROBERSP_PG * 128];
738 SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
739 SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
740 SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
Larry Finger0c817332010-12-08 11:12:31 -0600741
742 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
743
744 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
745
746 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
747 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
748 &reserved_page_packet[0], totalpacketlen);
749 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
750 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
751 u1RsvdPageLoc, 3);
752
753
754 skb = dev_alloc_skb(totalpacketlen);
755 memcpy((u8 *) skb_put(skb, totalpacketlen),
756 &reserved_page_packet, totalpacketlen);
757
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500758 rtstatus = _rtl92c_cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600759
760 if (rtstatus)
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500761 dlok = true;
Larry Finger0c817332010-12-08 11:12:31 -0600762
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500763 if (dlok) {
Larry Finger0c817332010-12-08 11:12:31 -0600764 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
765 ("Set RSVD page location to Fw.\n"));
766 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
767 "H2C_RSVDPAGE:\n",
768 u1RsvdPageLoc, 3);
769 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
770 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
771 } else
772 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
773 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
774}
Larry Finger1472d3a2011-02-23 10:24:58 -0600775EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600776
777void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
778{
779 u8 u1_joinbssrpt_parm[1] = {0};
780
781 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
782
783 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
784}
Larry Finger1472d3a2011-02-23 10:24:58 -0600785EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);