Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 31
 32#include <linux/firmware.h>
 33#include "../wifi.h"
 34#include "../pci.h"
 35#include "../base.h"
 36#include "../rtl8192ce/reg.h"
 37#include "../rtl8192ce/def.h"
 38#include "fw_common.h"
 39
 40static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
 41{
 42	struct rtl_priv *rtlpriv = rtl_priv(hw);
 43	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 44
 45	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
 46		u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 47		if (enable)
 48			value32 |= MCUFWDL_EN;
 49		else
 50			value32 &= ~MCUFWDL_EN;
 51		rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 52	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
 53		u8 tmp;
 54		if (enable) {
 55
 56			tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 57			rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
 58				       tmp | 0x04);
 59
 60			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
 61			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
 62
 63			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
 64			rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
 65		} else {
 66
 67			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
 68			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
 69
 70			rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
 71		}
 72	}
 73}
 74
 75static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
 76				   const u8 *buffer, u32 size)
 77{
 78	struct rtl_priv *rtlpriv = rtl_priv(hw);
 79	u32 blockSize = sizeof(u32);
 80	u8 *bufferPtr = (u8 *) buffer;
 81	u32 *pu4BytePtr = (u32 *) buffer;
 82	u32 i, offset, blockCount, remainSize;
 83
 84	blockCount = size / blockSize;
 85	remainSize = size % blockSize;
 86
 87	for (i = 0; i < blockCount; i++) {
 88		offset = i * blockSize;
 89		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
 90				*(pu4BytePtr + i));
 91	}
 92
 93	if (remainSize) {
 94		offset = blockCount * blockSize;
 95		bufferPtr += offset;
 96		for (i = 0; i < remainSize; i++) {
 97			rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
 98						 offset + i), *(bufferPtr + i));
 99		}
100	}
101}
102
103static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
104				  u32 page, const u8 *buffer, u32 size)
105{
106	struct rtl_priv *rtlpriv = rtl_priv(hw);
107	u8 value8;
108	u8 u8page = (u8) (page & 0x07);
109
110	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
111
112	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
113	_rtl92c_fw_block_write(hw, buffer, size);
114}
115
116static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
117{
118	u32 fwlen = *pfwlen;
119	u8 remain = (u8) (fwlen % 4);
120
121	remain = (remain == 0) ? 0 : (4 - remain);
122
123	while (remain > 0) {
124		pfwbuf[fwlen] = 0;
125		fwlen++;
126		remain--;
127	}
128
129	*pfwlen = fwlen;
130}
131
132static void _rtl92c_write_fw(struct ieee80211_hw *hw,
133			     enum version_8192c version, u8 *buffer, u32 size)
134{
135	struct rtl_priv *rtlpriv = rtl_priv(hw);
136	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
137	u8 *bufferPtr = (u8 *) buffer;
138
139	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
140
141	if (IS_CHIP_VER_B(version)) {
142		u32 pageNums, remainSize;
143		u32 page, offset;
144
145		if (IS_HARDWARE_TYPE_8192CE(rtlhal))
146			_rtl92c_fill_dummy(bufferPtr, &size);
147
148		pageNums = size / FW_8192C_PAGE_SIZE;
149		remainSize = size % FW_8192C_PAGE_SIZE;
150
151		if (pageNums > 4) {
152			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
153				 ("Page numbers should not greater then 4\n"));
154		}
155
156		for (page = 0; page < pageNums; page++) {
157			offset = page * FW_8192C_PAGE_SIZE;
158			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
159					      FW_8192C_PAGE_SIZE);
160		}
161
162		if (remainSize) {
163			offset = pageNums * FW_8192C_PAGE_SIZE;
164			page = pageNums;
165			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
166					      remainSize);
167		}
168	} else {
169		_rtl92c_fw_block_write(hw, buffer, size);
170	}
171}
172
173static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
174{
175	struct rtl_priv *rtlpriv = rtl_priv(hw);
176	u32 counter = 0;
177	u32 value32;
178
179	do {
180		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
181	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
182		 (!(value32 & FWDL_ChkSum_rpt)));
183
184	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
185		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
186			 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
187			  value32));
188		return -EIO;
189	}
190
191	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
192		 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
193
194	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
195	value32 |= MCUFWDL_RDY;
196	value32 &= ~WINTINI_RDY;
197	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
198
199	counter = 0;
200
201	do {
202		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
203		if (value32 & WINTINI_RDY) {
204			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
205				 ("Polling FW ready success!!"
206				 " REG_MCUFWDL:0x%08x .\n",
207				 value32));
208			return 0;
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	return -EIO;
218}
219
220int rtl92c_download_fw(struct ieee80211_hw *hw)
221{
222	struct rtl_priv *rtlpriv = rtl_priv(hw);
223	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
224	struct rtl92c_firmware_header *pfwheader;
225	u8 *pfwdata;
226	u32 fwsize;
227	enum version_8192c version = rtlhal->version;
228
229	pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
230	if (!rtlhal->pfirmware)
231		return 1;
232
233	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
234	pfwdata = (u8 *) rtlhal->pfirmware;
235	fwsize = rtlhal->fwsize;
236
237	if (IS_FW_HEADER_EXIST(pfwheader)) {
238		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
239			 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
240			  pfwheader->version, pfwheader->signature,
241			  (uint)sizeof(struct rtl92c_firmware_header)));
242
243		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
244		fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
245	}
246
247	_rtl92c_enable_fw_download(hw, true);
248	_rtl92c_write_fw(hw, version, pfwdata, fwsize);
249	_rtl92c_enable_fw_download(hw, false);
250
251	if (_rtl92c_fw_free_to_go(hw)) {
252		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
253			 ("Firmware is not ready to run!\n"));
254	} else {
255		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
256			 ("Firmware is ready to run!\n"));
257	}
258
259	return 0;
260}
261EXPORT_SYMBOL(rtl92c_download_fw);
262
263static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
264{
265	struct rtl_priv *rtlpriv = rtl_priv(hw);
266	u8 val_hmetfr, val_mcutst_1;
267	bool result = false;
268
269	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
270	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
271
272	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
273		result = true;
274	return result;
275}
276
277static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
278			      u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
279{
280	struct rtl_priv *rtlpriv = rtl_priv(hw);
281	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
282	u8 boxnum;
283	u16 box_reg = 0, box_extreg = 0;
284	u8 u1b_tmp;
285	bool isfw_read = false;
286	bool bwrite_sucess = false;
287	u8 wait_h2c_limmit = 100;
288	u8 wait_writeh2c_limmit = 100;
289	u8 boxcontent[4], boxextcontent[2];
290	u32 h2c_waitcounter = 0;
291	unsigned long flag;
292	u8 idx;
293
294	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
295
296	while (true) {
297		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
298		if (rtlhal->h2c_setinprogress) {
299			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
300				 ("H2C set in progress! Wait to set.."
301				  "element_id(%d).\n", element_id));
302
303			while (rtlhal->h2c_setinprogress) {
304				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
305						       flag);
306				h2c_waitcounter++;
307				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
308					 ("Wait 100 us (%d times)...\n",
309					  h2c_waitcounter));
310				udelay(100);
311
312				if (h2c_waitcounter > 1000)
313					return;
314				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
315						  flag);
316			}
317			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
318		} else {
319			rtlhal->h2c_setinprogress = true;
320			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
321			break;
322		}
323	}
324
325	while (!bwrite_sucess) {
326		wait_writeh2c_limmit--;
327		if (wait_writeh2c_limmit == 0) {
328			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
329				 ("Write H2C fail because no trigger "
330				  "for FW INT!\n"));
331			break;
332		}
333
334		boxnum = rtlhal->last_hmeboxnum;
335		switch (boxnum) {
336		case 0:
337			box_reg = REG_HMEBOX_0;
338			box_extreg = REG_HMEBOX_EXT_0;
339			break;
340		case 1:
341			box_reg = REG_HMEBOX_1;
342			box_extreg = REG_HMEBOX_EXT_1;
343			break;
344		case 2:
345			box_reg = REG_HMEBOX_2;
346			box_extreg = REG_HMEBOX_EXT_2;
347			break;
348		case 3:
349			box_reg = REG_HMEBOX_3;
350			box_extreg = REG_HMEBOX_EXT_3;
351			break;
352		default:
353			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
354				 ("switch case not process\n"));
355			break;
356		}
357
358		isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
359		while (!isfw_read) {
360
361			wait_h2c_limmit--;
362			if (wait_h2c_limmit == 0) {
363				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
364					 ("Wating too long for FW read "
365					  "clear HMEBox(%d)!\n", boxnum));
366				break;
367			}
368
369			udelay(10);
370
371			isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
372			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
373			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
374				 ("Wating for FW read clear HMEBox(%d)!!! "
375				  "0x1BF = %2x\n", boxnum, u1b_tmp));
376		}
377
378		if (!isfw_read) {
379			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
380				 ("Write H2C register BOX[%d] fail!!!!! "
381				  "Fw do not read.\n", boxnum));
382			break;
383		}
384
385		memset(boxcontent, 0, sizeof(boxcontent));
386		memset(boxextcontent, 0, sizeof(boxextcontent));
387		boxcontent[0] = element_id;
388		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
389			 ("Write element_id box_reg(%4x) = %2x\n",
390			  box_reg, element_id));
391
392		switch (cmd_len) {
393		case 1:
394			boxcontent[0] &= ~(BIT(7));
395			memcpy((u8 *) (boxcontent) + 1,
396			       p_cmdbuffer, 1);
397
398			for (idx = 0; idx < 4; idx++) {
399				rtl_write_byte(rtlpriv, box_reg + idx,
400					       boxcontent[idx]);
401			}
402			break;
403		case 2:
404			boxcontent[0] &= ~(BIT(7));
405			memcpy((u8 *) (boxcontent) + 1,
406			       p_cmdbuffer, 2);
407
408			for (idx = 0; idx < 4; idx++) {
409				rtl_write_byte(rtlpriv, box_reg + idx,
410					       boxcontent[idx]);
411			}
412			break;
413		case 3:
414			boxcontent[0] &= ~(BIT(7));
415			memcpy((u8 *) (boxcontent) + 1,
416			       p_cmdbuffer, 3);
417
418			for (idx = 0; idx < 4; idx++) {
419				rtl_write_byte(rtlpriv, box_reg + idx,
420					       boxcontent[idx]);
421			}
422			break;
423		case 4:
424			boxcontent[0] |= (BIT(7));
425			memcpy((u8 *) (boxextcontent),
426			       p_cmdbuffer, 2);
427			memcpy((u8 *) (boxcontent) + 1,
428			       p_cmdbuffer + 2, 2);
429
430			for (idx = 0; idx < 2; idx++) {
431				rtl_write_byte(rtlpriv, box_extreg + idx,
432					       boxextcontent[idx]);
433			}
434
435			for (idx = 0; idx < 4; idx++) {
436				rtl_write_byte(rtlpriv, box_reg + idx,
437					       boxcontent[idx]);
438			}
439			break;
440		case 5:
441			boxcontent[0] |= (BIT(7));
442			memcpy((u8 *) (boxextcontent),
443			       p_cmdbuffer, 2);
444			memcpy((u8 *) (boxcontent) + 1,
445			       p_cmdbuffer + 2, 3);
446
447			for (idx = 0; idx < 2; idx++) {
448				rtl_write_byte(rtlpriv, box_extreg + idx,
449					       boxextcontent[idx]);
450			}
451
452			for (idx = 0; idx < 4; idx++) {
453				rtl_write_byte(rtlpriv, box_reg + idx,
454					       boxcontent[idx]);
455			}
456			break;
457		default:
458			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
459				 ("switch case not process\n"));
460			break;
461		}
462
463		bwrite_sucess = true;
464
465		rtlhal->last_hmeboxnum = boxnum + 1;
466		if (rtlhal->last_hmeboxnum == 4)
467			rtlhal->last_hmeboxnum = 0;
468
469		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
470			 ("pHalData->last_hmeboxnum  = %d\n",
471			  rtlhal->last_hmeboxnum));
472	}
473
474	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
475	rtlhal->h2c_setinprogress = false;
476	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
477
478	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
479}
480
481void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
482			 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
483{
484	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
485	u32 tmp_cmdbuf[2];
486
487	if (rtlhal->fw_ready == false) {
488		RT_ASSERT(false, ("return H2C cmd because of Fw "
489				  "download fail!!!\n"));
490		return;
491	}
492
493	memset(tmp_cmdbuf, 0, 8);
494	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
495	_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
496
497	return;
498}
499EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
500
501void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
502{
503	u8 u1b_tmp;
504	u8 delay = 100;
505	struct rtl_priv *rtlpriv = rtl_priv(hw);
506
507	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
508	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
509
510	while (u1b_tmp & BIT(2)) {
511		delay--;
512		if (delay == 0) {
513			RT_ASSERT(false, ("8051 reset fail.\n"));
514			break;
515		}
516		udelay(50);
517		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
518	}
519}
520EXPORT_SYMBOL(rtl92c_firmware_selfreset);
521
522void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
523{
524	struct rtl_priv *rtlpriv = rtl_priv(hw);
525	u8 u1_h2c_set_pwrmode[3] = {0};
526	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
527
528	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
529
530	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
531	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
532	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
533					      ppsc->reg_max_lps_awakeintvl);
534
535	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
536		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
537		      u1_h2c_set_pwrmode, 3);
538	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
539
540}
541EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
542
543static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
544				struct sk_buff *skb)
545{
546	struct rtl_priv *rtlpriv = rtl_priv(hw);
547	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
548	struct rtl8192_tx_ring *ring;
549	struct rtl_tx_desc *pdesc;
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
563	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
564
565	__skb_queue_tail(&ring->queue, skb);
566
567	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
568
569	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
570
571	return true;
572}
573
574#define BEACON_PG		0 /*->1*/
575#define PSPOLL_PG		2
576#define NULL_PG			3
577#define PROBERSP_PG		4 /*->5*/
578
579#define TOTAL_RESERVED_PKT_LEN	768
580
581static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
582	/* page 0 beacon */
583	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
584	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
585	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
586	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
588	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
589	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
590	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
591	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
592	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
593	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
597	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599
600	/* page 1 beacon */
601	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
614	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617
618	/* page 2  ps-poll */
619	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
620	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
621	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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	0x18, 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 3  null */
637	0x48, 0x01, 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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
650	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
651	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653
654	/* page 4  probe_resp */
655	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
656	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
657	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
658	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
659	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
660	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
661	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
662	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
663	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
664	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
665	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
669	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671
672	/* page 5  probe_resp */
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	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};
690
691void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
692{
693	struct rtl_priv *rtlpriv = rtl_priv(hw);
694	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
695	struct sk_buff *skb = NULL;
696
697	u32 totalpacketlen;
698	bool rtstatus;
699	u8 u1RsvdPageLoc[3] = {0};
700	bool dlok = false;
701
702	u8 *beacon;
703	u8 *pspoll;
704	u8 *nullfunc;
705	u8 *probersp;
706	/*---------------------------------------------------------
707				(1) beacon
708	---------------------------------------------------------*/
709	beacon = &reserved_page_packet[BEACON_PG * 128];
710	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
711	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
712
713	/*-------------------------------------------------------
714				(2) ps-poll
715	--------------------------------------------------------*/
716	pspoll = &reserved_page_packet[PSPOLL_PG * 128];
717	SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
718	SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
719	SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
720
721	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
722
723	/*--------------------------------------------------------
724				(3) null data
725	---------------------------------------------------------*/
726	nullfunc = &reserved_page_packet[NULL_PG * 128];
727	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
728	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
729	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
730
731	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
732
733	/*---------------------------------------------------------
734				(4) probe response
735	----------------------------------------------------------*/
736	probersp = &reserved_page_packet[PROBERSP_PG * 128];
737	SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
738	SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
739	SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
740
741	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
742
743	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
744
745	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
746		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
747		      &reserved_page_packet[0], totalpacketlen);
748	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
749		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
750		      u1RsvdPageLoc, 3);
751
752
753	skb = dev_alloc_skb(totalpacketlen);
754	memcpy((u8 *) skb_put(skb, totalpacketlen),
755	       &reserved_page_packet, totalpacketlen);
756
757	rtstatus = _rtl92c_cmd_send_packet(hw, skb);
758
759	if (rtstatus)
760		dlok = true;
761
762	if (dlok) {
763		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
764			 ("Set RSVD page location to Fw.\n"));
765		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
766				"H2C_RSVDPAGE:\n",
767				u1RsvdPageLoc, 3);
768		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
769				    sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
770	} else
771		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
772			 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
773}
774EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
775
776void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
777{
778	u8 u1_joinbssrpt_parm[1] = {0};
779
780	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
781
782	rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
783}
784EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);