1 /******************************************************************************
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>.
25 * Larry Finger <Larry.Finger@lwfinger.net>
27 ******************************************************************************/
29 #define _RTL8712_CMD_C_
31 #include <linux/compiler.h>
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/slab.h>
35 #include <linux/module.h>
36 #include <linux/kref.h>
37 #include <linux/netdevice.h>
38 #include <linux/skbuff.h>
39 #include <linux/usb.h>
40 #include <linux/usb/ch9.h>
41 #include <linux/circ_buf.h>
42 #include <linux/uaccess.h>
43 #include <asm/byteorder.h>
44 #include <linux/atomic.h>
45 #include <linux/semaphore.h>
46 #include <linux/rtnetlink.h>
48 #include "osdep_service.h"
49 #include "drv_types.h"
50 #include "recv_osdep.h"
51 #include "mlme_osdep.h"
52 #include "rtl871x_ioctl_set.h"
54 static void check_hw_pbc(struct _adapter
*padapter
)
58 r8712_write8(padapter
, MAC_PINMUX_CTRL
, (GPIOMUX_EN
| GPIOSEL_GPIO
));
59 tmp1byte
= r8712_read8(padapter
, GPIO_IO_SEL
);
60 tmp1byte
&= ~(HAL_8192S_HW_GPIO_WPS_BIT
);
61 r8712_write8(padapter
, GPIO_IO_SEL
, tmp1byte
);
62 tmp1byte
= r8712_read8(padapter
, GPIO_CTRL
);
65 if (tmp1byte
& HAL_8192S_HW_GPIO_WPS_BIT
) {
66 /* Here we only set bPbcPressed to true
67 * After trigger PBC, the variable will be set to false
69 DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n");
70 /* 0 is the default value and it means the application monitors
71 * the HW PBC doesn't provide its pid to driver.
73 if (padapter
->pid
== 0)
75 kill_pid(find_vpid(padapter
->pid
), SIGUSR1
, 1);
79 /* query rx phy status from fw.
81 * Infrastructure mode: beacon , data.
83 static void query_fw_rx_phy_status(struct _adapter
*padapter
)
88 if (check_fwstate(&padapter
->mlmepriv
, _FW_LINKED
)) {
89 r8712_write32(padapter
, IOCMD_CTRL_REG
, 0xf4000001);
91 /* Wait FW complete IO Cmd */
92 while ((r8712_read32(padapter
, IOCMD_CTRL_REG
)) &&
98 val32
= r8712_read32(padapter
, IOCMD_DATA_REG
);
102 padapter
->recvpriv
.fw_rssi
=
103 (u8
)r8712_signal_scale_mapping(val32
);
107 /* check mlme, hw, phy, or dynamic algorithm status. */
108 static void StatusWatchdogCallback(struct _adapter
*padapter
)
110 check_hw_pbc(padapter
);
111 query_fw_rx_phy_status(padapter
);
114 static void r871x_internal_cmd_hdl(struct _adapter
*padapter
, u8
*pbuf
)
116 struct drvint_cmd_parm
*pdrvcmd
;
120 pdrvcmd
= (struct drvint_cmd_parm
*)pbuf
;
121 switch (pdrvcmd
->i_cid
) {
123 StatusWatchdogCallback(padapter
);
128 kfree(pdrvcmd
->pbuf
);
131 static u8
read_macreg_hdl(struct _adapter
*padapter
, u8
*pbuf
)
133 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
134 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
136 /* invoke cmd->callback function */
137 pcmd_callback
= cmd_callback
[pcmd
->cmdcode
].callback
;
139 r8712_free_cmd_obj(pcmd
);
141 pcmd_callback(padapter
, pcmd
);
145 static u8
write_macreg_hdl(struct _adapter
*padapter
, u8
*pbuf
)
147 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
148 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
150 /* invoke cmd->callback function */
151 pcmd_callback
= cmd_callback
[pcmd
->cmdcode
].callback
;
153 r8712_free_cmd_obj(pcmd
);
155 pcmd_callback(padapter
, pcmd
);
159 static u8
read_bbreg_hdl(struct _adapter
*padapter
, u8
*pbuf
)
162 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
163 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
165 if (pcmd
->rsp
&& pcmd
->rspsz
> 0)
166 memcpy(pcmd
->rsp
, (u8
*)&val
, pcmd
->rspsz
);
167 pcmd_callback
= cmd_callback
[pcmd
->cmdcode
].callback
;
169 r8712_free_cmd_obj(pcmd
);
171 pcmd_callback(padapter
, pcmd
);
175 static u8
write_bbreg_hdl(struct _adapter
*padapter
, u8
*pbuf
)
177 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
178 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
180 pcmd_callback
= cmd_callback
[pcmd
->cmdcode
].callback
;
182 r8712_free_cmd_obj(pcmd
);
184 pcmd_callback(padapter
, pcmd
);
188 static u8
read_rfreg_hdl(struct _adapter
*padapter
, u8
*pbuf
)
191 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
192 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
194 if (pcmd
->rsp
&& pcmd
->rspsz
> 0)
195 memcpy(pcmd
->rsp
, (u8
*)&val
, pcmd
->rspsz
);
196 pcmd_callback
= cmd_callback
[pcmd
->cmdcode
].callback
;
198 r8712_free_cmd_obj(pcmd
);
200 pcmd_callback(padapter
, pcmd
);
204 static u8
write_rfreg_hdl(struct _adapter
*padapter
, u8
*pbuf
)
206 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
207 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
209 pcmd_callback
= cmd_callback
[pcmd
->cmdcode
].callback
;
211 r8712_free_cmd_obj(pcmd
);
213 pcmd_callback(padapter
, pcmd
);
217 static u8
sys_suspend_hdl(struct _adapter
*padapter
, u8
*pbuf
)
219 struct cmd_obj
*pcmd
= (struct cmd_obj
*)pbuf
;
221 r8712_free_cmd_obj(pcmd
);
225 static struct cmd_obj
*cmd_hdl_filter(struct _adapter
*padapter
,
226 struct cmd_obj
*pcmd
)
228 struct cmd_obj
*pcmd_r
;
234 switch (pcmd
->cmdcode
) {
235 case GEN_CMD_CODE(_Read_MACREG
):
236 read_macreg_hdl(padapter
, (u8
*)pcmd
);
239 case GEN_CMD_CODE(_Write_MACREG
):
240 write_macreg_hdl(padapter
, (u8
*)pcmd
);
243 case GEN_CMD_CODE(_Read_BBREG
):
244 read_bbreg_hdl(padapter
, (u8
*)pcmd
);
246 case GEN_CMD_CODE(_Write_BBREG
):
247 write_bbreg_hdl(padapter
, (u8
*)pcmd
);
249 case GEN_CMD_CODE(_Read_RFREG
):
250 read_rfreg_hdl(padapter
, (u8
*)pcmd
);
252 case GEN_CMD_CODE(_Write_RFREG
):
253 write_rfreg_hdl(padapter
, (u8
*)pcmd
);
255 case GEN_CMD_CODE(_SetUsbSuspend
):
256 sys_suspend_hdl(padapter
, (u8
*)pcmd
);
258 case GEN_CMD_CODE(_JoinBss
):
259 r8712_joinbss_reset(padapter
);
260 /* Before set JoinBss_CMD to FW, driver must ensure FW is in
261 * PS_MODE_ACTIVE. Directly write rpwm to radio on and assign
262 * new pwr_mode to Driver, instead of use workitem to change
265 if (padapter
->pwrctrlpriv
.pwr_mode
> PS_MODE_ACTIVE
) {
266 padapter
->pwrctrlpriv
.pwr_mode
= PS_MODE_ACTIVE
;
267 mutex_lock(&padapter
->pwrctrlpriv
.mutex_lock
);
268 r8712_set_rpwm(padapter
, PS_STATE_S4
);
269 mutex_unlock(&padapter
->pwrctrlpriv
.mutex_lock
);
274 r871x_internal_cmd_hdl(padapter
, pcmd
->parmbuf
);
275 r8712_free_cmd_obj(pcmd
);
282 return pcmd_r
; /* if returning pcmd_r == NULL, pcmd must be free. */
285 static u8
check_cmd_fifo(struct _adapter
*padapter
, uint sz
)
290 u8
r8712_fw_cmd(struct _adapter
*pAdapter
, u32 cmd
)
292 int pollingcnts
= 50;
294 r8712_write32(pAdapter
, IOCMD_CTRL_REG
, cmd
);
296 while ((r8712_read32(pAdapter
, IOCMD_CTRL_REG
!= 0)) &&
301 if (pollingcnts
== 0)
306 void r8712_fw_cmd_data(struct _adapter
*pAdapter
, u32
*value
, u8 flag
)
308 if (flag
== 0) /* set */
309 r8712_write32(pAdapter
, IOCMD_DATA_REG
, *value
);
311 *value
= r8712_read32(pAdapter
, IOCMD_DATA_REG
);
314 int r8712_cmd_thread(void *context
)
316 struct cmd_obj
*pcmd
;
317 unsigned int cmdsz
, wr_sz
;
319 struct tx_desc
*pdesc
;
320 void (*pcmd_callback
)(struct _adapter
*dev
, struct cmd_obj
*pcmd
);
321 struct _adapter
*padapter
= context
;
322 struct cmd_priv
*pcmdpriv
= &(padapter
->cmdpriv
);
324 allow_signal(SIGTERM
);
326 if (wait_for_completion_interruptible(&pcmdpriv
->cmd_queue_comp
))
328 if (padapter
->bDriverStopped
|| padapter
->bSurpriseRemoved
)
330 if (r8712_register_cmd_alive(padapter
) != _SUCCESS
)
333 pcmd
= r8712_dequeue_cmd(&(pcmdpriv
->cmd_queue
));
335 r8712_unregister_cmd_alive(padapter
);
338 pcmdbuf
= (__le32
*)pcmdpriv
->cmd_buf
;
339 pdesc
= (struct tx_desc
*)pcmdbuf
;
340 memset(pdesc
, 0, TXDESC_SIZE
);
341 pcmd
= cmd_hdl_filter(padapter
, pcmd
);
342 if (pcmd
) { /* if pcmd != NULL, cmd will be handled by f/w */
343 struct dvobj_priv
*pdvobj
= &padapter
->dvobjpriv
;
346 pcmdpriv
->cmd_issued_cnt
++;
347 cmdsz
= round_up(pcmd
->cmdsz
, 8);
348 wr_sz
= TXDESC_SIZE
+ 8 + cmdsz
;
349 pdesc
->txdw0
|= cpu_to_le32((wr_sz
- TXDESC_SIZE
) &
351 if (pdvobj
->ishighspeed
) {
352 if ((wr_sz
% 512) == 0)
355 if ((wr_sz
% 64) == 0)
358 if (blnPending
) /* 32 bytes for TX Desc - 8 offset */
359 pdesc
->txdw0
|= cpu_to_le32(((TXDESC_SIZE
+
360 OFFSET_SZ
+ 8) << OFFSET_SHT
) &
363 pdesc
->txdw0
|= cpu_to_le32(((TXDESC_SIZE
+
368 pdesc
->txdw0
|= cpu_to_le32(OWN
| FSG
| LSG
);
369 pdesc
->txdw1
|= cpu_to_le32((0x13 << QSEL_SHT
) &
371 pcmdbuf
+= (TXDESC_SIZE
>> 2);
372 *pcmdbuf
= cpu_to_le32((cmdsz
& 0x0000ffff) |
373 (pcmd
->cmdcode
<< 16) |
374 (pcmdpriv
->cmd_seq
<< 24));
375 pcmdbuf
+= 2; /* 8 bytes alignment */
376 memcpy((u8
*)pcmdbuf
, pcmd
->parmbuf
, pcmd
->cmdsz
);
377 while (check_cmd_fifo(padapter
, wr_sz
) == _FAIL
) {
378 if (padapter
->bDriverStopped
||
379 padapter
->bSurpriseRemoved
)
385 wr_sz
+= 8; /* Append 8 bytes */
386 r8712_write_mem(padapter
, RTL8712_DMA_H2CCMD
, wr_sz
,
389 if (pcmd
->cmdcode
== GEN_CMD_CODE(_CreateBss
)) {
390 pcmd
->res
= H2C_SUCCESS
;
391 pcmd_callback
= cmd_callback
[pcmd
->
394 pcmd_callback(padapter
, pcmd
);
397 if (pcmd
->cmdcode
== GEN_CMD_CODE(_SetPwrMode
)) {
398 if (padapter
->pwrctrlpriv
.bSleep
) {
399 mutex_lock(&padapter
->
400 pwrctrlpriv
.mutex_lock
);
401 r8712_set_rpwm(padapter
, PS_STATE_S2
);
402 mutex_unlock(&padapter
->pwrctrlpriv
.mutex_lock
);
405 r8712_free_cmd_obj(pcmd
);
406 if (list_empty(&pcmdpriv
->cmd_queue
.queue
)) {
407 r8712_unregister_cmd_alive(padapter
);
415 flush_signals_thread();
417 /* free all cmd_obj resources */
419 pcmd
= r8712_dequeue_cmd(&(pcmdpriv
->cmd_queue
));
422 r8712_free_cmd_obj(pcmd
);
424 complete(&pcmdpriv
->terminate_cmdthread_comp
);
428 void r8712_event_handle(struct _adapter
*padapter
, __le32
*peventbuf
)
430 u8 evt_code
, evt_seq
;
432 void (*event_callback
)(struct _adapter
*dev
, u8
*pbuf
);
433 struct evt_priv
*pevt_priv
= &(padapter
->evtpriv
);
437 evt_sz
= (u16
)(le32_to_cpu(*peventbuf
) & 0xffff);
438 evt_seq
= (u8
)((le32_to_cpu(*peventbuf
) >> 24) & 0x7f);
439 evt_code
= (u8
)((le32_to_cpu(*peventbuf
) >> 16) & 0xff);
440 /* checking event sequence... */
441 if ((evt_seq
& 0x7f) != pevt_priv
->event_seq
) {
442 pevt_priv
->event_seq
= ((evt_seq
+ 1) & 0x7f);
445 /* checking if event code is valid */
446 if (evt_code
>= MAX_C2HEVT
) {
447 pevt_priv
->event_seq
= ((evt_seq
+ 1) & 0x7f);
449 } else if ((evt_code
== GEN_EVT_CODE(_Survey
)) &&
450 (evt_sz
> sizeof(struct wlan_bssid_ex
))) {
451 pevt_priv
->event_seq
= ((evt_seq
+ 1) & 0x7f);
454 /* checking if event size match the event parm size */
455 if ((wlanevents
[evt_code
].parmsize
) &&
456 (wlanevents
[evt_code
].parmsize
!= evt_sz
)) {
457 pevt_priv
->event_seq
= ((evt_seq
+ 1) & 0x7f);
459 } else if ((evt_sz
== 0) && (evt_code
!= GEN_EVT_CODE(_WPS_PBC
))) {
460 pevt_priv
->event_seq
= ((evt_seq
+ 1) & 0x7f);
463 pevt_priv
->event_seq
++; /* update evt_seq */
464 if (pevt_priv
->event_seq
> 127)
465 pevt_priv
->event_seq
= 0;
466 /* move to event content, 8 bytes alignment */
467 peventbuf
= peventbuf
+ 2;
468 event_callback
= wlanevents
[evt_code
].event_callback
;
470 event_callback(padapter
, (u8
*)peventbuf
);
471 pevt_priv
->evt_done_cnt
++;