Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
d217249d
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
d217249d
编写于
6月 22, 2012
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-linville' of
git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
上级
9ffddb1a
da0b1baa
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
332 addition
and
109 deletion
+332
-109
drivers/net/wireless/ti/wl12xx/cmd.c
drivers/net/wireless/ti/wl12xx/cmd.c
+10
-6
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl12xx/main.c
+3
-4
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wl18xx/main.c
+60
-45
drivers/net/wireless/ti/wlcore/acx.c
drivers/net/wireless/ti/wlcore/acx.c
+7
-1
drivers/net/wireless/ti/wlcore/acx.h
drivers/net/wireless/ti/wlcore/acx.h
+5
-0
drivers/net/wireless/ti/wlcore/cmd.h
drivers/net/wireless/ti/wlcore/cmd.h
+21
-0
drivers/net/wireless/ti/wlcore/conf.h
drivers/net/wireless/ti/wlcore/conf.h
+7
-1
drivers/net/wireless/ti/wlcore/debugfs.c
drivers/net/wireless/ti/wlcore/debugfs.c
+63
-0
drivers/net/wireless/ti/wlcore/ini.h
drivers/net/wireless/ti/wlcore/ini.h
+17
-5
drivers/net/wireless/ti/wlcore/init.c
drivers/net/wireless/ti/wlcore/init.c
+21
-22
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/main.c
+78
-19
drivers/net/wireless/ti/wlcore/ps.c
drivers/net/wireless/ti/wlcore/ps.c
+1
-1
drivers/net/wireless/ti/wlcore/rx.c
drivers/net/wireless/ti/wlcore/rx.c
+2
-2
drivers/net/wireless/ti/wlcore/rx.h
drivers/net/wireless/ti/wlcore/rx.h
+6
-0
drivers/net/wireless/ti/wlcore/testmode.c
drivers/net/wireless/ti/wlcore/testmode.c
+14
-0
drivers/net/wireless/ti/wlcore/tx.c
drivers/net/wireless/ti/wlcore/tx.c
+7
-3
drivers/net/wireless/ti/wlcore/wlcore.h
drivers/net/wireless/ti/wlcore/wlcore.h
+10
-0
未找到文件。
drivers/net/wireless/ti/wl12xx/cmd.c
浏览文件 @
d217249d
...
...
@@ -174,7 +174,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
struct
wl1271_nvs_file
*
nvs
=
(
struct
wl1271_nvs_file
*
)
wl
->
nvs
;
struct
wl1271_radio_parms_cmd
*
radio_parms
;
struct
wl1271_ini_general_params
*
gp
=
&
nvs
->
general_params
;
int
ret
;
int
ret
,
fem_idx
;
if
(
!
wl
->
nvs
)
return
-
ENODEV
;
...
...
@@ -185,11 +185,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms
->
test
.
id
=
TEST_CMD_INI_FILE_RADIO_PARAM
;
fem_idx
=
WL12XX_FEM_TO_NVS_ENTRY
(
gp
->
tx_bip_fem_manufacturer
);
/* 2.4GHz parameters */
memcpy
(
&
radio_parms
->
static_params_2
,
&
nvs
->
stat_radio_params_2
,
sizeof
(
struct
wl1271_ini_band_params_2
));
memcpy
(
&
radio_parms
->
dyn_params_2
,
&
nvs
->
dyn_radio_params_2
[
gp
->
tx_bip_fem_manufacturer
].
params
,
&
nvs
->
dyn_radio_params_2
[
fem_idx
].
params
,
sizeof
(
struct
wl1271_ini_fem_params_2
));
/* 5GHz parameters */
...
...
@@ -197,7 +199,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
&
nvs
->
stat_radio_params_5
,
sizeof
(
struct
wl1271_ini_band_params_5
));
memcpy
(
&
radio_parms
->
dyn_params_5
,
&
nvs
->
dyn_radio_params_5
[
gp
->
tx_bip_fem_manufacturer
].
params
,
&
nvs
->
dyn_radio_params_5
[
fem_idx
].
params
,
sizeof
(
struct
wl1271_ini_fem_params_5
));
wl1271_dump
(
DEBUG_CMD
,
"TEST_CMD_INI_FILE_RADIO_PARAM: "
,
...
...
@@ -216,7 +218,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
struct
wl128x_nvs_file
*
nvs
=
(
struct
wl128x_nvs_file
*
)
wl
->
nvs
;
struct
wl128x_radio_parms_cmd
*
radio_parms
;
struct
wl128x_ini_general_params
*
gp
=
&
nvs
->
general_params
;
int
ret
;
int
ret
,
fem_idx
;
if
(
!
wl
->
nvs
)
return
-
ENODEV
;
...
...
@@ -227,11 +229,13 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
radio_parms
->
test
.
id
=
TEST_CMD_INI_FILE_RADIO_PARAM
;
fem_idx
=
WL12XX_FEM_TO_NVS_ENTRY
(
gp
->
tx_bip_fem_manufacturer
);
/* 2.4GHz parameters */
memcpy
(
&
radio_parms
->
static_params_2
,
&
nvs
->
stat_radio_params_2
,
sizeof
(
struct
wl128x_ini_band_params_2
));
memcpy
(
&
radio_parms
->
dyn_params_2
,
&
nvs
->
dyn_radio_params_2
[
gp
->
tx_bip_fem_manufacturer
].
params
,
&
nvs
->
dyn_radio_params_2
[
fem_idx
].
params
,
sizeof
(
struct
wl128x_ini_fem_params_2
));
/* 5GHz parameters */
...
...
@@ -239,7 +243,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
&
nvs
->
stat_radio_params_5
,
sizeof
(
struct
wl128x_ini_band_params_5
));
memcpy
(
&
radio_parms
->
dyn_params_5
,
&
nvs
->
dyn_radio_params_5
[
gp
->
tx_bip_fem_manufacturer
].
params
,
&
nvs
->
dyn_radio_params_5
[
fem_idx
].
params
,
sizeof
(
struct
wl128x_ini_fem_params_5
));
radio_parms
->
fem_vendor_and_options
=
nvs
->
fem_vendor_and_options
;
...
...
drivers/net/wireless/ti/wl12xx/main.c
浏览文件 @
d217249d
...
...
@@ -246,6 +246,7 @@ static struct wlcore_conf wl12xx_conf = {
.
forced_ps
=
false
,
.
keep_alive_interval
=
55000
,
.
max_listen_interval
=
20
,
.
sta_sleep_auth
=
WL1271_PSM_ILLEGAL
,
},
.
itrim
=
{
.
enable
=
false
,
...
...
@@ -1448,10 +1449,8 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
wl
->
hw_min_ht_rate
=
WL12XX_CONF_HW_RXTX_RATE_MCS0
;
wl
->
fw_status_priv_len
=
0
;
wl
->
stats
.
fw_stats_len
=
sizeof
(
struct
wl12xx_acx_statistics
);
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_2GHZ
],
&
wl12xx_ht_cap
,
sizeof
(
wl12xx_ht_cap
));
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_5GHZ
],
&
wl12xx_ht_cap
,
sizeof
(
wl12xx_ht_cap
));
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_2GHZ
,
&
wl12xx_ht_cap
);
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_5GHZ
,
&
wl12xx_ht_cap
);
wl12xx_conf_init
(
wl
);
if
(
!
fref_param
)
{
...
...
drivers/net/wireless/ti/wl18xx/main.c
浏览文件 @
d217249d
...
...
@@ -43,10 +43,11 @@
#define WL18XX_RX_CHECKSUM_MASK 0x40
static
char
*
ht_mode_param
=
"
wide
"
;
static
char
*
ht_mode_param
=
"
default
"
;
static
char
*
board_type_param
=
"hdk"
;
static
bool
checksum_param
=
false
;
static
bool
enable_11a_param
=
true
;
static
int
num_rx_desc_param
=
-
1
;
/* phy paramters */
static
int
dc2dc_param
=
-
1
;
...
...
@@ -372,6 +373,7 @@ static struct wlcore_conf wl18xx_conf = {
.
forced_ps
=
false
,
.
keep_alive_interval
=
55000
,
.
max_listen_interval
=
20
,
.
sta_sleep_auth
=
WL1271_PSM_ILLEGAL
,
},
.
itrim
=
{
.
enable
=
false
,
...
...
@@ -606,8 +608,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
wl
->
plt_fw_name
=
WL18XX_FW_NAME
;
wl
->
quirks
|=
WLCORE_QUIRK_NO_ELP
|
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN
|
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN
|
WLCORE_QUIRK_TX_PAD_LAST_FRAME
;
break
;
case
CHIP_ID_185x_PG10
:
wl1271_debug
(
DEBUG_BOOT
,
"chip id 0x%x (185x PG10)"
,
...
...
@@ -1021,8 +1023,7 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
}
if
(
fw
->
size
!=
WL18XX_CONF_SIZE
)
{
wl1271_error
(
"configuration binary file size is wrong, "
"expected %ld got %zd"
,
wl1271_error
(
"configuration binary file size is wrong, expected %zu got %zu"
,
WL18XX_CONF_SIZE
,
fw
->
size
);
ret
=
-
EINVAL
;
goto
out
;
...
...
@@ -1214,8 +1215,8 @@ static struct wlcore_ops wl18xx_ops = {
.
pre_pkt_send
=
wl18xx_pre_pkt_send
,
};
/* HT cap appropriate for wide channels */
static
struct
ieee80211_sta_ht_cap
wl18xx_siso40_ht_cap
=
{
/* HT cap appropriate for wide channels
in 2Ghz
*/
static
struct
ieee80211_sta_ht_cap
wl18xx_siso40_ht_cap
_2ghz
=
{
.
cap
=
IEEE80211_HT_CAP_SGI_20
|
IEEE80211_HT_CAP_SGI_40
|
IEEE80211_HT_CAP_SUP_WIDTH_20_40
|
IEEE80211_HT_CAP_DSSSCCK40
,
.
ht_supported
=
true
,
...
...
@@ -1228,40 +1229,42 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = {
},
};
/* HT cap appropriate for SISO 20 */
static
struct
ieee80211_sta_ht_cap
wl18xx_siso20_ht_cap
=
{
.
cap
=
IEEE80211_HT_CAP_SGI_20
,
/* HT cap appropriate for wide channels in 5Ghz */
static
struct
ieee80211_sta_ht_cap
wl18xx_siso40_ht_cap_5ghz
=
{
.
cap
=
IEEE80211_HT_CAP_SGI_20
|
IEEE80211_HT_CAP_SGI_40
|
IEEE80211_HT_CAP_SUP_WIDTH_20_40
,
.
ht_supported
=
true
,
.
ampdu_factor
=
IEEE80211_HT_MAX_AMPDU_16K
,
.
ampdu_density
=
IEEE80211_HT_MPDU_DENSITY_16
,
.
mcs
=
{
.
rx_mask
=
{
0xff
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
},
.
rx_highest
=
cpu_to_le16
(
72
),
.
rx_highest
=
cpu_to_le16
(
150
),
.
tx_params
=
IEEE80211_HT_MCS_TX_DEFINED
,
},
};
/* HT cap appropriate for
MIMO rates in 20mhz channel
*/
static
struct
ieee80211_sta_ht_cap
wl18xx_
mimo_ht_cap_2ghz
=
{
/* HT cap appropriate for
SISO 20
*/
static
struct
ieee80211_sta_ht_cap
wl18xx_
siso20_ht_cap
=
{
.
cap
=
IEEE80211_HT_CAP_SGI_20
,
.
ht_supported
=
true
,
.
ampdu_factor
=
IEEE80211_HT_MAX_AMPDU_16K
,
.
ampdu_density
=
IEEE80211_HT_MPDU_DENSITY_16
,
.
mcs
=
{
.
rx_mask
=
{
0xff
,
0
xff
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
},
.
rx_highest
=
cpu_to_le16
(
144
),
.
rx_mask
=
{
0xff
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
},
.
rx_highest
=
cpu_to_le16
(
72
),
.
tx_params
=
IEEE80211_HT_MCS_TX_DEFINED
,
},
};
static
struct
ieee80211_sta_ht_cap
wl18xx_mimo_ht_cap_5ghz
=
{
/* HT cap appropriate for MIMO rates in 20mhz channel */
static
struct
ieee80211_sta_ht_cap
wl18xx_mimo_ht_cap_2ghz
=
{
.
cap
=
IEEE80211_HT_CAP_SGI_20
,
.
ht_supported
=
true
,
.
ampdu_factor
=
IEEE80211_HT_MAX_AMPDU_16K
,
.
ampdu_density
=
IEEE80211_HT_MPDU_DENSITY_16
,
.
mcs
=
{
.
rx_mask
=
{
0xff
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
},
.
rx_highest
=
cpu_to_le16
(
72
),
.
rx_mask
=
{
0xff
,
0
xff
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
},
.
rx_highest
=
cpu_to_le16
(
144
),
.
tx_params
=
IEEE80211_HT_MCS_TX_DEFINED
,
},
};
...
...
@@ -1286,7 +1289,7 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
wl
->
ptable
=
wl18xx_ptable
;
wl
->
rtable
=
wl18xx_rtable
;
wl
->
num_tx_desc
=
32
;
wl
->
num_rx_desc
=
16
;
wl
->
num_rx_desc
=
32
;
wl
->
band_rate_to_idx
=
wl18xx_band_rate_to_idx
;
wl
->
hw_tx_rate_tbl_size
=
WL18XX_CONF_HW_RXTX_RATE_MAX
;
wl
->
hw_min_ht_rate
=
WL18XX_CONF_HW_RXTX_RATE_MCS0
;
...
...
@@ -1294,32 +1297,8 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
wl
->
stats
.
fw_stats_len
=
sizeof
(
struct
wl18xx_acx_statistics
);
wl
->
static_data_priv_len
=
sizeof
(
struct
wl18xx_static_data_priv
);
if
(
!
strcmp
(
ht_mode_param
,
"wide"
))
{
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_2GHZ
],
&
wl18xx_siso40_ht_cap
,
sizeof
(
wl18xx_siso40_ht_cap
));
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_5GHZ
],
&
wl18xx_siso40_ht_cap
,
sizeof
(
wl18xx_siso40_ht_cap
));
}
else
if
(
!
strcmp
(
ht_mode_param
,
"mimo"
))
{
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_2GHZ
],
&
wl18xx_mimo_ht_cap_2ghz
,
sizeof
(
wl18xx_mimo_ht_cap_2ghz
));
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_5GHZ
],
&
wl18xx_mimo_ht_cap_5ghz
,
sizeof
(
wl18xx_mimo_ht_cap_5ghz
));
}
else
if
(
!
strcmp
(
ht_mode_param
,
"siso20"
))
{
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_2GHZ
],
&
wl18xx_siso20_ht_cap
,
sizeof
(
wl18xx_siso20_ht_cap
));
memcpy
(
&
wl
->
ht_cap
[
IEEE80211_BAND_5GHZ
],
&
wl18xx_siso20_ht_cap
,
sizeof
(
wl18xx_siso20_ht_cap
));
}
else
{
wl1271_error
(
"invalid ht_mode '%s'"
,
ht_mode_param
);
ret
=
-
EINVAL
;
goto
out_free
;
}
if
(
num_rx_desc_param
!=
-
1
)
wl
->
num_rx_desc
=
num_rx_desc_param
;
ret
=
wl18xx_conf_init
(
wl
,
&
pdev
->
dev
);
if
(
ret
<
0
)
...
...
@@ -1366,6 +1345,37 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
if
(
dc2dc_param
!=
-
1
)
priv
->
conf
.
phy
.
external_pa_dc2dc
=
dc2dc_param
;
if
(
!
strcmp
(
ht_mode_param
,
"default"
))
{
/*
* Only support mimo with multiple antennas. Fall back to
* siso20.
*/
if
(
priv
->
conf
.
phy
.
number_of_assembled_ant2_4
>=
2
)
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_2GHZ
,
&
wl18xx_mimo_ht_cap_2ghz
);
else
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_2GHZ
,
&
wl18xx_siso20_ht_cap
);
/* 5Ghz is always wide */
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_5GHZ
,
&
wl18xx_siso40_ht_cap_5ghz
);
}
else
if
(
!
strcmp
(
ht_mode_param
,
"wide"
))
{
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_2GHZ
,
&
wl18xx_siso40_ht_cap_2ghz
);
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_5GHZ
,
&
wl18xx_siso40_ht_cap_5ghz
);
}
else
if
(
!
strcmp
(
ht_mode_param
,
"siso20"
))
{
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_2GHZ
,
&
wl18xx_siso20_ht_cap
);
wlcore_set_ht_cap
(
wl
,
IEEE80211_BAND_5GHZ
,
&
wl18xx_siso20_ht_cap
);
}
else
{
wl1271_error
(
"invalid ht_mode '%s'"
,
ht_mode_param
);
ret
=
-
EINVAL
;
goto
out_free
;
}
if
(
!
checksum_param
)
{
wl18xx_ops
.
set_rx_csum
=
NULL
;
wl18xx_ops
.
init_vif
=
NULL
;
...
...
@@ -1410,7 +1420,7 @@ static void __exit wl18xx_exit(void)
module_exit
(
wl18xx_exit
);
module_param_named
(
ht_mode
,
ht_mode_param
,
charp
,
S_IRUSR
);
MODULE_PARM_DESC
(
ht_mode
,
"Force HT mode: wide
(default), mimo
or siso20"
);
MODULE_PARM_DESC
(
ht_mode
,
"Force HT mode: wide or siso20"
);
module_param_named
(
board_type
,
board_type_param
,
charp
,
S_IRUSR
);
MODULE_PARM_DESC
(
board_type
,
"Board type: fpga, hdk (default), evb, com8 or "
...
...
@@ -1458,6 +1468,11 @@ module_param_named(pwr_limit_reference_11_abg,
MODULE_PARM_DESC
(
pwr_limit_reference_11_abg
,
"Power limit reference: u8 "
"(default is 0xc8)"
);
module_param_named
(
num_rx_desc
,
num_rx_desc_param
,
int
,
S_IRUSR
);
MODULE_PARM_DESC
(
num_rx_desc_param
,
"Number of Rx descriptors: u8 (default is 32)"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_AUTHOR
(
"Luciano Coelho <coelho@ti.com>"
);
MODULE_FIRMWARE
(
WL18XX_FW_NAME
);
drivers/net/wireless/ti/wlcore/acx.c
浏览文件 @
d217249d
...
...
@@ -70,7 +70,7 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
struct
acx_sleep_auth
*
auth
;
int
ret
;
wl1271_debug
(
DEBUG_ACX
,
"acx sleep auth
"
);
wl1271_debug
(
DEBUG_ACX
,
"acx sleep auth
%d"
,
sleep_auth
);
auth
=
kzalloc
(
sizeof
(
*
auth
),
GFP_KERNEL
);
if
(
!
auth
)
{
...
...
@@ -81,7 +81,13 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
auth
->
sleep_auth
=
sleep_auth
;
ret
=
wl1271_cmd_configure
(
wl
,
ACX_SLEEP_AUTH
,
auth
,
sizeof
(
*
auth
));
if
(
ret
<
0
)
{
wl1271_error
(
"could not configure sleep_auth to %d: %d"
,
sleep_auth
,
ret
);
goto
out
;
}
wl
->
sleep_auth
=
sleep_auth
;
out:
kfree
(
auth
);
return
ret
;
...
...
drivers/net/wireless/ti/wlcore/acx.h
浏览文件 @
d217249d
...
...
@@ -118,6 +118,11 @@ enum wl1271_psm_mode {
/* Extreme low power */
WL1271_PSM_ELP
=
2
,
WL1271_PSM_MAX
=
WL1271_PSM_ELP
,
/* illegal out of band value of PSM mode */
WL1271_PSM_ILLEGAL
=
0xff
};
struct
acx_sleep_auth
{
...
...
drivers/net/wireless/ti/wlcore/cmd.h
浏览文件 @
d217249d
...
...
@@ -652,4 +652,25 @@ struct wl12xx_cmd_stop_channel_switch {
struct
wl1271_cmd_header
header
;
}
__packed
;
/* Used to check radio status after calibration */
#define MAX_TLV_LENGTH 500
#define TEST_CMD_P2G_CAL 2
/* TX BiP */
struct
wl1271_cmd_cal_p2g
{
struct
wl1271_cmd_header
header
;
struct
wl1271_cmd_test_header
test
;
__le32
ver
;
__le16
len
;
u8
buf
[
MAX_TLV_LENGTH
];
u8
type
;
u8
padding
;
__le16
radio_status
;
u8
sub_band_mask
;
u8
padding2
;
}
__packed
;
#endif
/* __WL1271_CMD_H__ */
drivers/net/wireless/ti/wlcore/conf.h
浏览文件 @
d217249d
...
...
@@ -951,6 +951,12 @@ struct conf_conn_settings {
* Range: u16
*/
u8
max_listen_interval
;
/*
* Default sleep authorization for a new STA interface. This determines
* whether we can go to ELP.
*/
u8
sta_sleep_auth
;
}
__packed
;
enum
{
...
...
@@ -1276,7 +1282,7 @@ struct conf_hangover_settings {
* version, the two LSB are the lower driver's private conf
* version.
*/
#define WLCORE_CONF_VERSION (0x000
1
<< 16)
#define WLCORE_CONF_VERSION (0x000
2
<< 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
...
...
drivers/net/wireless/ti/wlcore/debugfs.c
浏览文件 @
d217249d
...
...
@@ -963,6 +963,68 @@ static const struct file_operations fw_stats_raw_ops = {
.
llseek
=
default_llseek
,
};
static
ssize_t
sleep_auth_read
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
wl1271
*
wl
=
file
->
private_data
;
return
wl1271_format_buffer
(
user_buf
,
count
,
ppos
,
"%d
\n
"
,
wl
->
sleep_auth
);
}
static
ssize_t
sleep_auth_write
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
wl1271
*
wl
=
file
->
private_data
;
unsigned
long
value
;
int
ret
;
ret
=
kstrtoul_from_user
(
user_buf
,
count
,
0
,
&
value
);
if
(
ret
<
0
)
{
wl1271_warning
(
"illegal value in sleep_auth"
);
return
-
EINVAL
;
}
if
(
value
<
0
||
value
>
WL1271_PSM_MAX
)
{
wl1271_warning
(
"sleep_auth must be between 0 and %d"
,
WL1271_PSM_MAX
);
return
-
ERANGE
;
}
mutex_lock
(
&
wl
->
mutex
);
wl
->
conf
.
conn
.
sta_sleep_auth
=
value
;
if
(
wl
->
state
==
WL1271_STATE_OFF
)
{
/* this will show up on "read" in case we are off */
wl
->
sleep_auth
=
value
;
goto
out
;
}
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_acx_sleep_auth
(
wl
,
value
);
if
(
ret
<
0
)
goto
out_sleep
;
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
count
;
}
static
const
struct
file_operations
sleep_auth_ops
=
{
.
read
=
sleep_auth_read
,
.
write
=
sleep_auth_write
,
.
open
=
simple_open
,
.
llseek
=
default_llseek
,
};
static
int
wl1271_debugfs_add_files
(
struct
wl1271
*
wl
,
struct
dentry
*
rootdir
)
{
...
...
@@ -988,6 +1050,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD
(
irq_blk_threshold
,
rootdir
);
DEBUGFS_ADD
(
irq_timeout
,
rootdir
);
DEBUGFS_ADD
(
fw_stats_raw
,
rootdir
);
DEBUGFS_ADD
(
sleep_auth
,
rootdir
);
streaming
=
debugfs_create_dir
(
"rx_streaming"
,
rootdir
);
if
(
!
streaming
||
IS_ERR
(
streaming
))
...
...
drivers/net/wireless/ti/wlcore/ini.h
浏览文件 @
d217249d
...
...
@@ -172,7 +172,19 @@ struct wl128x_ini_fem_params_5 {
/* NVS data structure */
#define WL1271_INI_NVS_SECTION_SIZE 468
#define WL1271_INI_FEM_MODULE_COUNT 2
/* We have four FEM module types: 0-RFMD, 1-TQS, 2-SKW, 3-TQS_HP */
#define WL1271_INI_FEM_MODULE_COUNT 4
/*
* In NVS we only store two FEM module entries -
* FEM modules 0,2,3 are stored in entry 0
* FEM module 1 is stored in entry 1
*/
#define WL12XX_NVS_FEM_MODULE_COUNT 2
#define WL12XX_FEM_TO_NVS_ENTRY(ini_fem_module) \
((ini_fem_module) == 1 ? 1 : 0)
#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
...
...
@@ -188,13 +200,13 @@ struct wl1271_nvs_file {
struct
{
struct
wl1271_ini_fem_params_2
params
;
u8
padding
;
}
dyn_radio_params_2
[
WL12
71_INI
_FEM_MODULE_COUNT
];
}
dyn_radio_params_2
[
WL12
XX_NVS
_FEM_MODULE_COUNT
];
struct
wl1271_ini_band_params_5
stat_radio_params_5
;
u8
padding3
;
struct
{
struct
wl1271_ini_fem_params_5
params
;
u8
padding
;
}
dyn_radio_params_5
[
WL12
71_INI
_FEM_MODULE_COUNT
];
}
dyn_radio_params_5
[
WL12
XX_NVS
_FEM_MODULE_COUNT
];
}
__packed
;
struct
wl128x_nvs_file
{
...
...
@@ -209,12 +221,12 @@ struct wl128x_nvs_file {
struct
{
struct
wl128x_ini_fem_params_2
params
;
u8
padding
;
}
dyn_radio_params_2
[
WL12
71_INI
_FEM_MODULE_COUNT
];
}
dyn_radio_params_2
[
WL12
XX_NVS
_FEM_MODULE_COUNT
];
struct
wl128x_ini_band_params_5
stat_radio_params_5
;
u8
padding3
;
struct
{
struct
wl128x_ini_fem_params_5
params
;
u8
padding
;
}
dyn_radio_params_5
[
WL12
71_INI
_FEM_MODULE_COUNT
];
}
dyn_radio_params_5
[
WL12
XX_NVS
_FEM_MODULE_COUNT
];
}
__packed
;
#endif
drivers/net/wireless/ti/wlcore/init.c
浏览文件 @
d217249d
...
...
@@ -554,29 +554,28 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
bool
is_ap
=
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
);
int
ret
,
i
;
/*
* consider all existing roles before configuring psm.
* TODO: reconfigure on interface removal.
*/
if
(
!
wl
->
ap_count
)
{
if
(
is_ap
)
{
/* Configure for power always on */
/* consider all existing roles before configuring psm. */
if
(
wl
->
ap_count
==
0
&&
is_ap
)
{
/* first AP */
/* Configure for power always on */
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_CAM
);
if
(
ret
<
0
)
return
ret
;
/* first STA, no APs */
}
else
if
(
wl
->
sta_count
==
0
&&
wl
->
ap_count
==
0
&&
!
is_ap
)
{
u8
sta_auth
=
wl
->
conf
.
conn
.
sta_sleep_auth
;
/* Configure for power according to debugfs */
if
(
sta_auth
!=
WL1271_PSM_ILLEGAL
)
ret
=
wl1271_acx_sleep_auth
(
wl
,
sta_auth
);
/* Configure for power always on */
else
if
(
wl
->
quirks
&
WLCORE_QUIRK_NO_ELP
)
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_CAM
);
if
(
ret
<
0
)
return
ret
;
}
else
if
(
!
wl
->
sta_count
)
{
if
(
wl
->
quirks
&
WLCORE_QUIRK_NO_ELP
)
{
/* Configure for power always on */
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_CAM
);
if
(
ret
<
0
)
return
ret
;
}
else
{
/* Configure for ELP power saving */
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_ELP
);
if
(
ret
<
0
)
return
ret
;
}
}
/* Configure for ELP power saving */
else
ret
=
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_ELP
);
if
(
ret
<
0
)
return
ret
;
}
/* Mode specific init */
...
...
drivers/net/wireless/ti/wlcore/main.c
浏览文件 @
d217249d
...
...
@@ -770,14 +770,16 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
return
len
;
}
#define WLCORE_FW_LOG_END 0x2000000
static
void
wl12xx_read_fwlog_panic
(
struct
wl1271
*
wl
)
{
u32
addr
;
u32
first_addr
;
u32
offset
;
u32
end_of_log
;
u8
*
block
;
if
((
wl
->
quirks
&
WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED
)
||
(
wl
->
conf
.
fwlog
.
mode
!=
WL12XX_FWLOG_ON_DEMAND
)
||
(
wl
->
conf
.
fwlog
.
mem_blocks
==
0
))
return
;
...
...
@@ -791,19 +793,26 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
* Make sure the chip is awake and the logger isn't active.
* Do not send a stop fwlog command if the fw is hanged.
*/
if
(
!
wl1271_ps_elp_wakeup
(
wl
)
&&
!
wl
->
watchdog_recovery
)
wl12xx_cmd_stop_fwlog
(
wl
);
else
if
(
wl1271_ps_elp_wakeup
(
wl
))
goto
out
;
if
(
!
wl
->
watchdog_recovery
)
wl12xx_cmd_stop_fwlog
(
wl
);
/* Read the first memory block address */
wl12xx_fw_status
(
wl
,
wl
->
fw_status_1
,
wl
->
fw_status_2
);
first_
addr
=
le32_to_cpu
(
wl
->
fw_status_2
->
log_start_addr
);
if
(
!
first_
addr
)
addr
=
le32_to_cpu
(
wl
->
fw_status_2
->
log_start_addr
);
if
(
!
addr
)
goto
out
;
if
(
wl
->
conf
.
fwlog
.
mode
==
WL12XX_FWLOG_CONTINUOUS
)
{
offset
=
sizeof
(
addr
)
+
sizeof
(
struct
wl1271_rx_descriptor
);
end_of_log
=
WLCORE_FW_LOG_END
;
}
else
{
offset
=
sizeof
(
addr
);
end_of_log
=
addr
;
}
/* Traverse the memory blocks linked list */
addr
=
first_addr
;
do
{
memset
(
block
,
0
,
WL12XX_HW_BLOCK_SIZE
);
wl1271_read_hwaddr
(
wl
,
addr
,
block
,
WL12XX_HW_BLOCK_SIZE
,
...
...
@@ -812,13 +821,14 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
/*
* Memory blocks are linked to one another. The first 4 bytes
* of each memory block hold the hardware address of the next
* one. The last memory block points to the first one.
* one. The last memory block points to the first one in
* on demand mode and is equal to 0x2000000 in continuous mode.
*/
addr
=
le32_to_cpup
((
__le32
*
)
block
);
if
(
!
wl12xx_copy_fwlog
(
wl
,
block
+
sizeof
(
addr
)
,
WL12XX_HW_BLOCK_SIZE
-
sizeof
(
addr
)
))
if
(
!
wl12xx_copy_fwlog
(
wl
,
block
+
offset
,
WL12XX_HW_BLOCK_SIZE
-
offset
))
break
;
}
while
(
addr
&&
(
addr
!=
first_addr
));
}
while
(
addr
&&
(
addr
!=
end_of_log
));
wake_up_interruptible
(
&
wl
->
fwlog_waitq
);
...
...
@@ -1082,6 +1092,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
mutex_lock
(
&
wl
->
mutex
);
wl1271_power_off
(
wl
);
wl
->
flags
=
0
;
wl
->
sleep_auth
=
WL1271_PSM_ILLEGAL
;
wl
->
state
=
WL1271_STATE_OFF
;
wl
->
plt
=
false
;
wl
->
rx_counter
=
0
;
...
...
@@ -1740,6 +1751,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl
->
ap_fw_ps_map
=
0
;
wl
->
ap_ps_map
=
0
;
wl
->
sched_scanning
=
false
;
wl
->
sleep_auth
=
WL1271_PSM_ILLEGAL
;
memset
(
wl
->
roles_map
,
0
,
sizeof
(
wl
->
roles_map
));
memset
(
wl
->
links_map
,
0
,
sizeof
(
wl
->
links_map
));
memset
(
wl
->
roc_map
,
0
,
sizeof
(
wl
->
roc_map
));
...
...
@@ -2146,6 +2158,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
{
struct
wl12xx_vif
*
wlvif
=
wl12xx_vif_to_data
(
vif
);
int
i
,
ret
;
bool
is_ap
=
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
);
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 remove interface"
);
...
...
@@ -2226,11 +2239,25 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wlvif
->
role_id
=
WL12XX_INVALID_ROLE_ID
;
wlvif
->
dev_role_id
=
WL12XX_INVALID_ROLE_ID
;
if
(
wlvif
->
bss_type
==
BSS_TYPE_AP_BSS
)
if
(
is_ap
)
wl
->
ap_count
--
;
else
wl
->
sta_count
--
;
/* Last AP, have more stations. Configure according to STA. */
if
(
wl
->
ap_count
==
0
&&
is_ap
&&
wl
->
sta_count
)
{
u8
sta_auth
=
wl
->
conf
.
conn
.
sta_sleep_auth
;
/* Configure for power according to debugfs */
if
(
sta_auth
!=
WL1271_PSM_ILLEGAL
)
wl1271_acx_sleep_auth
(
wl
,
sta_auth
);
/* Configure for power always on */
else
if
(
wl
->
quirks
&
WLCORE_QUIRK_NO_ELP
)
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_CAM
);
/* Configure for ELP power saving */
else
wl1271_acx_sleep_auth
(
wl
,
WL1271_PSM_ELP
);
}
mutex_unlock
(
&
wl
->
mutex
);
del_timer_sync
(
&
wlvif
->
rx_streaming_timer
);
...
...
@@ -2454,6 +2481,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
wlvif
->
channel_type
=
conf
->
channel_type
;
if
(
is_ap
)
{
wl1271_set_band_rate
(
wl
,
wlvif
);
ret
=
wl1271_init_ap_rates
(
wl
,
wlvif
);
if
(
ret
<
0
)
wl1271_error
(
"AP rate policy change failed %d"
,
...
...
@@ -4090,16 +4118,13 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
static
int
wl1271_op_get_survey
(
struct
ieee80211_hw
*
hw
,
int
idx
,
struct
survey_info
*
survey
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
struct
ieee80211_conf
*
conf
=
&
hw
->
conf
;
if
(
idx
!=
0
)
return
-
ENOENT
;
survey
->
channel
=
conf
->
channel
;
survey
->
filled
=
SURVEY_INFO_NOISE_DBM
;
survey
->
noise
=
wl
->
noise
;
survey
->
filled
=
0
;
return
0
;
}
...
...
@@ -4365,9 +4390,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
case
IEEE80211_AMPDU_RX_STOP
:
if
(
!
(
*
ba_bitmap
&
BIT
(
tid
)))
{
ret
=
-
EINVAL
;
wl1271_error
(
"no active RX BA session on tid: %d"
,
/*
* this happens on reconfig - so only output a debug
* message for now, and don't fail the function.
*/
wl1271_debug
(
DEBUG_MAC80211
,
"no active RX BA session on tid: %d"
,
tid
);
ret
=
0
;
break
;
}
...
...
@@ -4976,6 +5006,29 @@ static void wl1271_unregister_hw(struct wl1271 *wl)
}
static
const
struct
ieee80211_iface_limit
wlcore_iface_limits
[]
=
{
{
.
max
=
2
,
.
types
=
BIT
(
NL80211_IFTYPE_STATION
),
},
{
.
max
=
1
,
.
types
=
BIT
(
NL80211_IFTYPE_AP
)
|
BIT
(
NL80211_IFTYPE_P2P_GO
)
|
BIT
(
NL80211_IFTYPE_P2P_CLIENT
),
},
};
static
const
struct
ieee80211_iface_combination
wlcore_iface_combinations
[]
=
{
{
.
num_different_channels
=
1
,
.
max_interfaces
=
2
,
.
limits
=
wlcore_iface_limits
,
.
n_limits
=
ARRAY_SIZE
(
wlcore_iface_limits
),
},
};
static
int
wl1271_init_ieee80211
(
struct
wl1271
*
wl
)
{
static
const
u32
cipher_suites
[]
=
{
...
...
@@ -5069,6 +5122,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P
;
/* allowed interface combinations */
wl
->
hw
->
wiphy
->
iface_combinations
=
wlcore_iface_combinations
;
wl
->
hw
->
wiphy
->
n_iface_combinations
=
ARRAY_SIZE
(
wlcore_iface_combinations
);
SET_IEEE80211_DEV
(
wl
->
hw
,
wl
->
dev
);
wl
->
hw
->
sta_data_size
=
sizeof
(
struct
wl1271_station
);
...
...
@@ -5140,6 +5198,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
wl
->
channel_type
=
NL80211_CHAN_NO_HT
;
wl
->
flags
=
0
;
wl
->
sg_enabled
=
true
;
wl
->
sleep_auth
=
WL1271_PSM_ILLEGAL
;
wl
->
hw_pg_ver
=
-
1
;
wl
->
ap_ps_map
=
0
;
wl
->
ap_fw_ps_map
=
0
;
...
...
drivers/net/wireless/ti/wlcore/ps.c
浏览文件 @
d217249d
...
...
@@ -76,7 +76,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
struct
wl12xx_vif
*
wlvif
;
u32
timeout
;
if
(
wl
->
quirks
&
WLCORE_QUIRK_NO
_ELP
)
if
(
wl
->
sleep_auth
!=
WL1271_PSM
_ELP
)
return
;
/* we shouldn't get consecutive sleep requests */
...
...
drivers/net/wireless/ti/wlcore/rx.c
浏览文件 @
d217249d
...
...
@@ -127,7 +127,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
}
if
(
rx_align
==
WLCORE_RX_BUF_UNALIGNED
)
reserved
=
NET_IP
_ALIGN
;
reserved
=
RX_BUF
_ALIGN
;
/* the data read starts with the descriptor */
desc
=
(
struct
wl1271_rx_descriptor
*
)
data
;
...
...
@@ -175,7 +175,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
*/
memcpy
(
buf
,
data
+
sizeof
(
*
desc
),
pkt_data_len
);
if
(
rx_align
==
WLCORE_RX_BUF_PADDED
)
skb_pull
(
skb
,
NET_IP
_ALIGN
);
skb_pull
(
skb
,
RX_BUF
_ALIGN
);
*
hlid
=
desc
->
hlid
;
...
...
drivers/net/wireless/ti/wlcore/rx.h
浏览文件 @
d217249d
...
...
@@ -103,6 +103,12 @@
/* If set, the buffer was padded by the FW to be 4 bytes aligned */
#define RX_BUF_PADDED_PAYLOAD BIT(30)
/*
* Account for the padding inserted by the FW in case of RX_ALIGNMENT
* or for fixing alignment in case the packet wasn't aligned.
*/
#define RX_BUF_ALIGN 2
/* Describes the alignment state of a Rx buffer */
enum
wl_rx_buf_align
{
WLCORE_RX_BUF_ALIGNED
,
...
...
drivers/net/wireless/ti/wlcore/testmode.c
浏览文件 @
d217249d
...
...
@@ -108,6 +108,20 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
}
if
(
answer
)
{
/* If we got bip calibration answer print radio status */
struct
wl1271_cmd_cal_p2g
*
params
=
(
struct
wl1271_cmd_cal_p2g
*
)
buf
;
s16
radio_status
=
(
s16
)
le16_to_cpu
(
params
->
radio_status
);
if
(
params
->
test
.
id
==
TEST_CMD_P2G_CAL
&&
radio_status
<
0
)
wl1271_warning
(
"testmode cmd: radio status=%d"
,
radio_status
);
else
wl1271_info
(
"testmode cmd: radio status=%d"
,
radio_status
);
len
=
nla_total_size
(
buf_len
);
skb
=
cfg80211_testmode_alloc_reply_skb
(
wl
->
hw
->
wiphy
,
len
);
if
(
!
skb
)
{
...
...
drivers/net/wireless/ti/wlcore/tx.c
浏览文件 @
d217249d
...
...
@@ -305,11 +305,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if
(
is_dummy
||
!
wlvif
)
rate_idx
=
0
;
else
if
(
wlvif
->
bss_type
!=
BSS_TYPE_AP_BSS
)
{
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default
basic rates */
/*
* if the packets are destined for AP (have a STA entry)
* send them with AP rate policies (EAPOLs are an exception),
* otherwise use default basic rates
*/
if
(
control
->
flags
&
IEEE80211_TX_CTL_NO_CCK_RATE
)
rate_idx
=
wlvif
->
sta
.
p2p_rate_idx
;
else
if
(
skb
->
protocol
==
cpu_to_be16
(
ETH_P_PAE
))
rate_idx
=
wlvif
->
sta
.
basic_rate_idx
;
else
if
(
control
->
control
.
sta
)
rate_idx
=
wlvif
->
sta
.
ap_rate_idx
;
else
...
...
drivers/net/wireless/ti/wlcore/wlcore.h
浏览文件 @
d217249d
...
...
@@ -387,6 +387,9 @@ struct wl1271 {
/* mutex for protecting the tx_flush function */
struct
mutex
flush_mutex
;
/* sleep auth value currently configured to FW */
int
sleep_auth
;
};
int
__devinit
wlcore_probe
(
struct
wl1271
*
wl
,
struct
platform_device
*
pdev
);
...
...
@@ -398,6 +401,13 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
key_conf
);
static
inline
void
wlcore_set_ht_cap
(
struct
wl1271
*
wl
,
enum
ieee80211_band
band
,
struct
ieee80211_sta_ht_cap
*
ht_cap
)
{
memcpy
(
&
wl
->
ht_cap
[
band
],
ht_cap
,
sizeof
(
*
ht_cap
));
}
/* Firmware image load chunk size */
#define CHUNK_SIZE 16384
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录