blob: f107660f545dc71c92074a9b8a937971baee7406 [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;
Larry Finger25b2bc32011-02-11 14:34:03 -0600226 const struct firmware *firmware;
Larry Finger0c817332010-12-08 11:12:31 -0600227
Larry Finger32473282011-03-27 16:19:57 -0500228 printk(KERN_INFO "rtl8192c: Loading firmware file %s\n",
Larry Finger25b2bc32011-02-11 14:34:03 -0600229 rtlpriv->cfg->fw_name);
Larry Finger32473282011-03-27 16:19:57 -0500230 if (request_firmware(&firmware, rtlpriv->cfg->fw_name,
231 rtlpriv->io.dev)) {
232 printk(KERN_ERR "rtl8192c: Firmware loading failed\n");
Larry Finger0c817332010-12-08 11:12:31 -0600233 return 1;
234 }
235
236 if (firmware->size > 0x4000) {
237 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
238 ("Firmware is too big!\n"));
239 release_firmware(firmware);
240 return 1;
241 }
242
243 memcpy(rtlhal->pfirmware, firmware->data, firmware->size);
244 fwsize = firmware->size;
245 release_firmware(firmware);
246
247 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
248 pfwdata = (u8 *) rtlhal->pfirmware;
249
250 if (IS_FW_HEADER_EXIST(pfwheader)) {
251 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
252 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
253 pfwheader->version, pfwheader->signature,
254 (uint)sizeof(struct rtl92c_firmware_header)));
255
256 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
257 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
258 }
259
260 _rtl92c_enable_fw_download(hw, true);
261 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
262 _rtl92c_enable_fw_download(hw, false);
263
Larry Finger32473282011-03-27 16:19:57 -0500264 if (_rtl92c_fw_free_to_go(hw)) {
Larry Finger0c817332010-12-08 11:12:31 -0600265 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
266 ("Firmware is not ready to run!\n"));
267 } else {
268 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
269 ("Firmware is ready to run!\n"));
270 }
271
272 return 0;
273}
Larry Finger1472d3a2011-02-23 10:24:58 -0600274EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600275
276static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
277{
278 struct rtl_priv *rtlpriv = rtl_priv(hw);
279 u8 val_hmetfr, val_mcutst_1;
280 bool result = false;
281
282 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
283 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
284
285 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
286 result = true;
287 return result;
288}
289
290static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
291 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
292{
293 struct rtl_priv *rtlpriv = rtl_priv(hw);
294 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
295 u8 boxnum;
296 u16 box_reg, box_extreg;
297 u8 u1b_tmp;
298 bool isfw_read = false;
Larry Finger0c817332010-12-08 11:12:31 -0600299 bool bwrite_sucess = false;
300 u8 wait_h2c_limmit = 100;
301 u8 wait_writeh2c_limmit = 100;
302 u8 boxcontent[4], boxextcontent[2];
303 u32 h2c_waitcounter = 0;
304 unsigned long flag;
305 u8 idx;
306
307 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
308
309 while (true) {
310 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600311 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600312 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
313 ("H2C set in progress! Wait to set.."
314 "element_id(%d).\n", element_id));
315
Larry Finger7ea47242011-02-19 16:28:57 -0600316 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600317 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
318 flag);
319 h2c_waitcounter++;
320 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
321 ("Wait 100 us (%d times)...\n",
322 h2c_waitcounter));
323 udelay(100);
324
325 if (h2c_waitcounter > 1000)
326 return;
327 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
328 flag);
329 }
330 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
331 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600332 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600333 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
334 break;
335 }
336 }
337
338 while (!bwrite_sucess) {
339 wait_writeh2c_limmit--;
340 if (wait_writeh2c_limmit == 0) {
341 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
342 ("Write H2C fail because no trigger "
343 "for FW INT!\n"));
344 break;
345 }
346
347 boxnum = rtlhal->last_hmeboxnum;
348 switch (boxnum) {
349 case 0:
350 box_reg = REG_HMEBOX_0;
351 box_extreg = REG_HMEBOX_EXT_0;
352 break;
353 case 1:
354 box_reg = REG_HMEBOX_1;
355 box_extreg = REG_HMEBOX_EXT_1;
356 break;
357 case 2:
358 box_reg = REG_HMEBOX_2;
359 box_extreg = REG_HMEBOX_EXT_2;
360 break;
361 case 3:
362 box_reg = REG_HMEBOX_3;
363 box_extreg = REG_HMEBOX_EXT_3;
364 break;
365 default:
366 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
367 ("switch case not process\n"));
368 break;
369 }
370
371 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
372 while (!isfw_read) {
373
374 wait_h2c_limmit--;
375 if (wait_h2c_limmit == 0) {
376 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
377 ("Wating too long for FW read "
378 "clear HMEBox(%d)!\n", boxnum));
379 break;
380 }
381
382 udelay(10);
383
384 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
385 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
386 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
387 ("Wating for FW read clear HMEBox(%d)!!! "
388 "0x1BF = %2x\n", boxnum, u1b_tmp));
389 }
390
391 if (!isfw_read) {
392 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
393 ("Write H2C register BOX[%d] fail!!!!! "
394 "Fw do not read.\n", boxnum));
395 break;
396 }
397
398 memset(boxcontent, 0, sizeof(boxcontent));
399 memset(boxextcontent, 0, sizeof(boxextcontent));
400 boxcontent[0] = element_id;
401 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
402 ("Write element_id box_reg(%4x) = %2x\n",
403 box_reg, element_id));
404
405 switch (cmd_len) {
406 case 1:
407 boxcontent[0] &= ~(BIT(7));
408 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500409 p_cmdbuffer, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600410
411 for (idx = 0; idx < 4; idx++) {
412 rtl_write_byte(rtlpriv, box_reg + idx,
413 boxcontent[idx]);
414 }
415 break;
416 case 2:
417 boxcontent[0] &= ~(BIT(7));
418 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500419 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600420
421 for (idx = 0; idx < 4; idx++) {
422 rtl_write_byte(rtlpriv, box_reg + idx,
423 boxcontent[idx]);
424 }
425 break;
426 case 3:
427 boxcontent[0] &= ~(BIT(7));
428 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500429 p_cmdbuffer, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600430
431 for (idx = 0; idx < 4; idx++) {
432 rtl_write_byte(rtlpriv, box_reg + idx,
433 boxcontent[idx]);
434 }
435 break;
436 case 4:
437 boxcontent[0] |= (BIT(7));
438 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500439 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600440 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500441 p_cmdbuffer + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600442
443 for (idx = 0; idx < 2; idx++) {
444 rtl_write_byte(rtlpriv, box_extreg + idx,
445 boxextcontent[idx]);
446 }
447
448 for (idx = 0; idx < 4; idx++) {
449 rtl_write_byte(rtlpriv, box_reg + idx,
450 boxcontent[idx]);
451 }
452 break;
453 case 5:
454 boxcontent[0] |= (BIT(7));
455 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500456 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600457 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500458 p_cmdbuffer + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600459
460 for (idx = 0; idx < 2; idx++) {
461 rtl_write_byte(rtlpriv, box_extreg + idx,
462 boxextcontent[idx]);
463 }
464
465 for (idx = 0; idx < 4; idx++) {
466 rtl_write_byte(rtlpriv, box_reg + idx,
467 boxcontent[idx]);
468 }
469 break;
470 default:
471 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
472 ("switch case not process\n"));
473 break;
474 }
475
476 bwrite_sucess = true;
477
478 rtlhal->last_hmeboxnum = boxnum + 1;
479 if (rtlhal->last_hmeboxnum == 4)
480 rtlhal->last_hmeboxnum = 0;
481
482 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
483 ("pHalData->last_hmeboxnum = %d\n",
484 rtlhal->last_hmeboxnum));
485 }
486
487 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600488 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600489 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
490
491 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
492}
493
494void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
495 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
496{
497 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
498 u32 tmp_cmdbuf[2];
499
Larry Finger7ea47242011-02-19 16:28:57 -0600500 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600501 RT_ASSERT(false, ("return H2C cmd because of Fw "
502 "download fail!!!\n"));
503 return;
504 }
505
506 memset(tmp_cmdbuf, 0, 8);
507 memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
508 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
509
510 return;
511}
Larry Finger1472d3a2011-02-23 10:24:58 -0600512EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600513
514void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
515{
516 u8 u1b_tmp;
517 u8 delay = 100;
518 struct rtl_priv *rtlpriv = rtl_priv(hw);
519
520 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
521 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
522
523 while (u1b_tmp & BIT(2)) {
524 delay--;
525 if (delay == 0) {
526 RT_ASSERT(false, ("8051 reset fail.\n"));
527 break;
528 }
529 udelay(50);
530 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
531 }
532}
Larry Finger1472d3a2011-02-23 10:24:58 -0600533EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600534
535void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
536{
537 struct rtl_priv *rtlpriv = rtl_priv(hw);
538 u8 u1_h2c_set_pwrmode[3] = {0};
539 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
540
541 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
542
543 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
544 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
545 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
546 ppsc->reg_max_lps_awakeintvl);
547
548 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
549 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
550 u1_h2c_set_pwrmode, 3);
551 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
552
553}
Larry Finger1472d3a2011-02-23 10:24:58 -0600554EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600555
Larry Finger0c817332010-12-08 11:12:31 -0600556#define BEACON_PG 0 /*->1*/
557#define PSPOLL_PG 2
558#define NULL_PG 3
559#define PROBERSP_PG 4 /*->5*/
560
561#define TOTAL_RESERVED_PKT_LEN 768
562
563static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
564 /* page 0 beacon */
565 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
566 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
567 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
570 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
571 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
572 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
573 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
574 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
575 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
579 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
581
582 /* page 1 beacon */
583 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599
600 /* page 2 ps-poll */
601 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
602 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
615 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617
618 /* page 3 null */
619 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
620 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
621 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
633 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635
636 /* page 4 probe_resp */
637 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
638 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
639 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
640 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
641 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
642 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
643 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
644 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
645 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
646 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
647 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
651 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653
654 /* page 5 probe_resp */
655 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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};
672
673void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
674{
675 struct rtl_priv *rtlpriv = rtl_priv(hw);
676 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
677 struct sk_buff *skb = NULL;
678
679 u32 totalpacketlen;
680 bool rtstatus;
681 u8 u1RsvdPageLoc[3] = {0};
682 bool b_dlok = false;
683
684 u8 *beacon;
685 u8 *p_pspoll;
686 u8 *nullfunc;
687 u8 *p_probersp;
688 /*---------------------------------------------------------
689 (1) beacon
690 ---------------------------------------------------------*/
691 beacon = &reserved_page_packet[BEACON_PG * 128];
692 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
693 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
694
695 /*-------------------------------------------------------
696 (2) ps-poll
697 --------------------------------------------------------*/
698 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
699 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
700 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
701 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
702
703 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
704
705 /*--------------------------------------------------------
706 (3) null data
707 ---------------------------------------------------------*/
708 nullfunc = &reserved_page_packet[NULL_PG * 128];
709 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
710 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
711 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
712
713 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
714
715 /*---------------------------------------------------------
716 (4) probe response
717 ----------------------------------------------------------*/
718 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
719 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
720 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
721 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
722
723 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
724
725 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
726
727 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
728 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
729 &reserved_page_packet[0], totalpacketlen);
730 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
731 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
732 u1RsvdPageLoc, 3);
733
734
735 skb = dev_alloc_skb(totalpacketlen);
736 memcpy((u8 *) skb_put(skb, totalpacketlen),
737 &reserved_page_packet, totalpacketlen);
738
Larry Finger25b2bc32011-02-11 14:34:03 -0600739 rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600740
741 if (rtstatus)
742 b_dlok = true;
743
744 if (b_dlok) {
745 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
746 ("Set RSVD page location to Fw.\n"));
747 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
748 "H2C_RSVDPAGE:\n",
749 u1RsvdPageLoc, 3);
750 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
751 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
752 } else
753 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
754 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
755}
Larry Finger1472d3a2011-02-23 10:24:58 -0600756EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600757
758void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
759{
760 u8 u1_joinbssrpt_parm[1] = {0};
761
762 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
763
764 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
765}
Larry Finger1472d3a2011-02-23 10:24:58 -0600766EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);