Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
917879fe
提交
917879fe
authored
12月 17, 2010
作者:
Moises Silva
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of git.freeswitch.org:freeswitch
上级
6e24e8e6
ae7279f1
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
166 行增加
和
31 行删除
+166
-31
main.c
src/mod/endpoints/mod_skypopen/oss/main.c
+146
-22
skypopen.h
src/mod/endpoints/mod_skypopen/oss/skypopen.h
+17
-6
switch_channel.c
src/switch_channel.c
+2
-0
switch_core_state_machine.c
src/switch_core_state_machine.c
+1
-3
没有找到文件。
src/mod/endpoints/mod_skypopen/oss/main.c
浏览文件 @
917879fe
...
@@ -60,15 +60,18 @@ MODULE_LICENSE("Dual BSD/GPL");
...
@@ -60,15 +60,18 @@ MODULE_LICENSE("Dual BSD/GPL");
static
struct
skypopen_dev
*
skypopen_devices
;
/* allocated in skypopen_init_module */
static
struct
skypopen_dev
*
skypopen_devices
;
/* allocated in skypopen_init_module */
#define GIOVA_BLK 1920
static
int
unload
=
0
;
#define GIOVA_SLEEP 20
#ifdef CENTOS
#define HRTIMER_MODE_REL HRTIMER_REL
#endif// CENTOS
#ifndef WANT_HRTIMER
void
my_timer_callback_inq
(
unsigned
long
data
)
void
my_timer_callback_inq
(
unsigned
long
data
)
{
{
struct
skypopen_dev
*
dev
=
(
void
*
)
data
;
struct
skypopen_dev
*
dev
=
(
void
*
)
data
;
wake_up_interruptible
(
&
dev
->
inq
);
wake_up_interruptible
(
&
dev
->
inq
);
mod_timer
(
&
dev
->
timer_inq
,
jiffies
+
msecs_to_jiffies
(
GIOVA
_SLEEP
)
);
mod_timer
(
&
dev
->
timer_inq
,
jiffies
+
msecs_to_jiffies
(
SKYPOPEN
_SLEEP
)
);
}
}
...
@@ -77,8 +80,66 @@ void my_timer_callback_outq( unsigned long data )
...
@@ -77,8 +80,66 @@ void my_timer_callback_outq( unsigned long data )
struct
skypopen_dev
*
dev
=
(
void
*
)
data
;
struct
skypopen_dev
*
dev
=
(
void
*
)
data
;
wake_up_interruptible
(
&
dev
->
outq
);
wake_up_interruptible
(
&
dev
->
outq
);
mod_timer
(
&
dev
->
timer_outq
,
jiffies
+
msecs_to_jiffies
(
GIOVA
_SLEEP
)
);
mod_timer
(
&
dev
->
timer_outq
,
jiffies
+
msecs_to_jiffies
(
SKYPOPEN
_SLEEP
)
);
}
}
#else// WANT_HRTIMER
#ifndef CENTOS
static
enum
hrtimer_restart
my_hrtimer_callback_inq
(
struct
hrtimer
*
timer_inq
)
{
struct
skypopen_dev
*
dev
=
container_of
(
timer_inq
,
struct
skypopen_dev
,
timer_inq
);
ktime_t
now
;
if
(
unload
)
return
HRTIMER_NORESTART
;
now
=
ktime_get
();
hrtimer_forward
(
&
dev
->
timer_inq
,
now
,
ktime_set
(
0
,
SKYPOPEN_SLEEP
*
1000000
));
wake_up_interruptible
(
&
dev
->
inq
);
return
HRTIMER_RESTART
;
}
static
enum
hrtimer_restart
my_hrtimer_callback_outq
(
struct
hrtimer
*
timer_outq
)
{
struct
skypopen_dev
*
dev
=
container_of
(
timer_outq
,
struct
skypopen_dev
,
timer_outq
);
ktime_t
now
;
if
(
unload
)
return
HRTIMER_NORESTART
;
now
=
ktime_get
();
hrtimer_forward
(
&
dev
->
timer_outq
,
now
,
ktime_set
(
0
,
SKYPOPEN_SLEEP
*
1000000
));
wake_up_interruptible
(
&
dev
->
outq
);
return
HRTIMER_RESTART
;
}
#else// CENTOS
static
int
my_hrtimer_callback_inq
(
struct
hrtimer
*
timer_inq
)
{
struct
skypopen_dev
*
dev
=
container_of
(
timer_inq
,
struct
skypopen_dev
,
timer_inq
);
if
(
unload
)
return
HRTIMER_NORESTART
;
hrtimer_forward
(
&
dev
->
timer_inq
,
timer_inq
->
expires
,
ktime_set
(
0
,
SKYPOPEN_SLEEP
*
1000000
));
wake_up_interruptible
(
&
dev
->
inq
);
return
HRTIMER_RESTART
;
}
static
int
my_hrtimer_callback_outq
(
struct
hrtimer
*
timer_outq
)
{
struct
skypopen_dev
*
dev
=
container_of
(
timer_outq
,
struct
skypopen_dev
,
timer_outq
);
if
(
unload
)
return
HRTIMER_NORESTART
;
hrtimer_forward
(
&
dev
->
timer_outq
,
timer_outq
->
expires
,
ktime_set
(
0
,
SKYPOPEN_SLEEP
*
1000000
));
wake_up_interruptible
(
&
dev
->
outq
);
return
HRTIMER_RESTART
;
}
#endif// CENTOS
#endif// WANT_HRTIMER
/* The clone-specific data structure includes a key field */
/* The clone-specific data structure includes a key field */
...
@@ -97,6 +158,12 @@ static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED;
...
@@ -97,6 +158,12 @@ static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED;
static
struct
skypopen_dev
*
skypopen_c_lookfor_device
(
dev_t
key
)
static
struct
skypopen_dev
*
skypopen_c_lookfor_device
(
dev_t
key
)
{
{
struct
skypopen_listitem
*
lptr
;
struct
skypopen_listitem
*
lptr
;
#ifdef WANT_HRTIMER
#if 0
ktime_t ktime_inq;
ktime_t ktime_outq;
#endif //0
#endif// WANT_HRTIMER
list_for_each_entry
(
lptr
,
&
skypopen_c_list
,
list
)
{
list_for_each_entry
(
lptr
,
&
skypopen_c_list
,
list
)
{
if
(
lptr
->
key
==
key
)
if
(
lptr
->
key
==
key
)
...
@@ -112,14 +179,29 @@ static struct skypopen_dev *skypopen_c_lookfor_device(dev_t key)
...
@@ -112,14 +179,29 @@ static struct skypopen_dev *skypopen_c_lookfor_device(dev_t key)
memset
(
lptr
,
0
,
sizeof
(
struct
skypopen_listitem
));
memset
(
lptr
,
0
,
sizeof
(
struct
skypopen_listitem
));
lptr
->
key
=
key
;
lptr
->
key
=
key
;
init_waitqueue_head
(
&
lptr
->
device
.
inq
);
init_waitqueue_head
(
&
lptr
->
device
.
inq
);
init_waitqueue_head
(
&
lptr
->
device
.
outq
);
init_waitqueue_head
(
&
lptr
->
device
.
outq
);
setup_timer
(
&
lptr
->
device
.
timer_inq
,
my_timer_callback_inq
,
(
long
int
)
lptr
);
#ifndef WANT_HRTIMER
setup_timer
(
&
lptr
->
device
.
timer_outq
,
my_timer_callback_outq
,
(
long
int
)
lptr
);
setup_timer
(
&
lptr
->
device
.
timer_inq
,
my_timer_callback_inq
,
(
long
int
)
lptr
);
printk
(
"Starting skypopen OSS driver read timer (%dms) skype client:(%d)
\n
"
,
GIOVA_SLEEP
,
current
->
tgid
);
setup_timer
(
&
lptr
->
device
.
timer_outq
,
my_timer_callback_outq
,
(
long
int
)
lptr
);
mod_timer
(
&
lptr
->
device
.
timer_inq
,
jiffies
+
msecs_to_jiffies
(
GIOVA_SLEEP
)
);
printk
(
"Starting skypopen OSS driver read timer (%dms) skype client:(%d)
\n
"
,
SKYPOPEN_SLEEP
,
current
->
tgid
);
printk
(
"Starting skypopen OSS driver write timer (%dms) skype client:(%d)
\n
"
,
GIOVA_SLEEP
,
current
->
tgid
);
mod_timer
(
&
lptr
->
device
.
timer_inq
,
jiffies
+
msecs_to_jiffies
(
SKYPOPEN_SLEEP
)
);
mod_timer
(
&
lptr
->
device
.
timer_outq
,
jiffies
+
msecs_to_jiffies
(
GIOVA_SLEEP
)
);
printk
(
"Starting skypopen OSS driver write timer (%dms) skype client:(%d)
\n
"
,
SKYPOPEN_SLEEP
,
current
->
tgid
);
mod_timer
(
&
lptr
->
device
.
timer_outq
,
jiffies
+
msecs_to_jiffies
(
SKYPOPEN_SLEEP
)
);
#else// WANT_HRTIMER
#if 0
ktime_inq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000);
hrtimer_init( &lptr->device.timer_inq, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
lptr->device.timer_inq.function = &my_hrtimer_callback_inq;
hrtimer_start( &lptr->device.timer_inq, ktime_inq, HRTIMER_MODE_REL );
ktime_outq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000);
hrtimer_init( &lptr->device.timer_outq, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
lptr->device.timer_outq.function = &my_hrtimer_callback_outq;
hrtimer_start( &lptr->device.timer_outq, ktime_outq, HRTIMER_MODE_REL );
#endif
#endif// WANT_HRTIMER
/* place it in the list */
/* place it in the list */
list_add
(
&
lptr
->
list
,
&
skypopen_c_list
);
list_add
(
&
lptr
->
list
,
&
skypopen_c_list
);
...
@@ -135,7 +217,7 @@ static int skypopen_c_open(struct inode *inode, struct file *filp)
...
@@ -135,7 +217,7 @@ static int skypopen_c_open(struct inode *inode, struct file *filp)
struct
skypopen_dev
*
dev
;
struct
skypopen_dev
*
dev
;
dev_t
key
;
dev_t
key
;
key
=
current
->
p
id
;
key
=
current
->
tg
id
;
/* look for a skypopenc device in the list */
/* look for a skypopenc device in the list */
spin_lock
(
&
skypopen_c_lock
);
spin_lock
(
&
skypopen_c_lock
);
...
@@ -163,12 +245,27 @@ static int skypopen_c_release(struct inode *inode, struct file *filp)
...
@@ -163,12 +245,27 @@ static int skypopen_c_release(struct inode *inode, struct file *filp)
/*************************************************************/
/*************************************************************/
ssize_t
skypopen_read
(
struct
file
*
filp
,
char
__user
*
buf
,
size_t
count
,
s
tatic
s
size_t
skypopen_read
(
struct
file
*
filp
,
char
__user
*
buf
,
size_t
count
,
loff_t
*
f_pos
)
loff_t
*
f_pos
)
{
{
struct
skypopen_dev
*
dev
=
filp
->
private_data
;
DEFINE_WAIT
(
wait
);
DEFINE_WAIT
(
wait
);
struct
skypopen_dev
*
dev
=
filp
->
private_data
;
#ifdef WANT_HRTIMER
#if 1
if
(
dev
->
timer_inq_started
==
0
){
ktime_t
ktime_inq
;
ktime_inq
=
ktime_set
(
0
,
SKYPOPEN_SLEEP
*
1000000
);
hrtimer_init
(
&
dev
->
timer_inq
,
CLOCK_MONOTONIC
,
HRTIMER_MODE_REL
);
dev
->
timer_inq
.
function
=
&
my_hrtimer_callback_inq
;
hrtimer_start
(
&
dev
->
timer_inq
,
ktime_inq
,
HRTIMER_MODE_REL
);
dev
->
timer_inq_started
=
1
;
}
#endif
#endif// WANT_HRTIMER
//printk("READ\n");
prepare_to_wait
(
&
dev
->
inq
,
&
wait
,
TASK_INTERRUPTIBLE
);
prepare_to_wait
(
&
dev
->
inq
,
&
wait
,
TASK_INTERRUPTIBLE
);
schedule
();
schedule
();
finish_wait
(
&
dev
->
inq
,
&
wait
);
finish_wait
(
&
dev
->
inq
,
&
wait
);
...
@@ -176,12 +273,27 @@ ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
...
@@ -176,12 +273,27 @@ ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
}
}
ssize_t
skypopen_write
(
struct
file
*
filp
,
const
char
__user
*
buf
,
size_t
count
,
s
tatic
s
size_t
skypopen_write
(
struct
file
*
filp
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
f_pos
)
loff_t
*
f_pos
)
{
{
struct
skypopen_dev
*
dev
=
filp
->
private_data
;
DEFINE_WAIT
(
wait
);
DEFINE_WAIT
(
wait
);
struct
skypopen_dev
*
dev
=
filp
->
private_data
;
#ifdef WANT_HRTIMER
#if 1
if
(
dev
->
timer_outq_started
==
0
){
ktime_t
ktime_outq
;
ktime_outq
=
ktime_set
(
0
,
SKYPOPEN_SLEEP
*
1000000
);
hrtimer_init
(
&
dev
->
timer_outq
,
CLOCK_MONOTONIC
,
HRTIMER_MODE_REL
);
dev
->
timer_outq
.
function
=
&
my_hrtimer_callback_outq
;
hrtimer_start
(
&
dev
->
timer_outq
,
ktime_outq
,
HRTIMER_MODE_REL
);
dev
->
timer_outq_started
=
1
;
}
#endif
#endif// WANT_HRTIMER
//printk("WRITE\n");
prepare_to_wait
(
&
dev
->
outq
,
&
wait
,
TASK_INTERRUPTIBLE
);
prepare_to_wait
(
&
dev
->
outq
,
&
wait
,
TASK_INTERRUPTIBLE
);
schedule
();
schedule
();
finish_wait
(
&
dev
->
outq
,
&
wait
);
finish_wait
(
&
dev
->
outq
,
&
wait
);
...
@@ -192,7 +304,7 @@ ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
...
@@ -192,7 +304,7 @@ ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
* The ioctl() implementation
* The ioctl() implementation
*/
*/
int
skypopen_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
static
int
skypopen_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
void
__user
*
argp
=
(
void
__user
*
)
arg
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
...
@@ -202,7 +314,7 @@ int skypopen_ioctl(struct inode *inode, struct file *filp,
...
@@ -202,7 +314,7 @@ int skypopen_ioctl(struct inode *inode, struct file *filp,
case
OSS_GETVERSION
:
case
OSS_GETVERSION
:
return
put_user
(
SOUND_VERSION
,
p
);
return
put_user
(
SOUND_VERSION
,
p
);
case
SNDCTL_DSP_GETBLKSIZE
:
case
SNDCTL_DSP_GETBLKSIZE
:
return
put_user
(
GIOVA
_BLK
,
p
);
return
put_user
(
SKYPOPEN
_BLK
,
p
);
case
SNDCTL_DSP_GETFMTS
:
case
SNDCTL_DSP_GETFMTS
:
return
put_user
(
28731
,
p
);
return
put_user
(
28731
,
p
);
...
@@ -239,6 +351,11 @@ void skypopen_cleanup_module(void)
...
@@ -239,6 +351,11 @@ void skypopen_cleanup_module(void)
struct
skypopen_listitem
*
lptr
,
*
next
;
struct
skypopen_listitem
*
lptr
,
*
next
;
dev_t
devno
=
MKDEV
(
skypopen_major
,
skypopen_minor
);
dev_t
devno
=
MKDEV
(
skypopen_major
,
skypopen_minor
);
unload
=
1
;
msleep
(
100
);
/* Get rid of our char dev entries */
/* Get rid of our char dev entries */
if
(
skypopen_devices
)
{
if
(
skypopen_devices
)
{
for
(
i
=
0
;
i
<
skypopen_nr_devs
;
i
++
)
{
for
(
i
=
0
;
i
<
skypopen_nr_devs
;
i
++
)
{
...
@@ -247,13 +364,20 @@ void skypopen_cleanup_module(void)
...
@@ -247,13 +364,20 @@ void skypopen_cleanup_module(void)
kfree
(
skypopen_devices
);
kfree
(
skypopen_devices
);
}
}
/* And all the cloned devices */
/* And all the cloned devices */
list_for_each_entry_safe
(
lptr
,
next
,
&
skypopen_c_list
,
list
)
{
list_for_each_entry_safe
(
lptr
,
next
,
&
skypopen_c_list
,
list
)
{
#ifndef WANT_HRTIMER
ret
=
del_timer
(
&
lptr
->
device
.
timer_inq
);
ret
=
del_timer
(
&
lptr
->
device
.
timer_inq
);
//printk( "Stopped skypopen OSS driver read timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid
);
printk
(
"Stopped skypopen OSS driver read timer
\n
"
);
ret
=
del_timer
(
&
lptr
->
device
.
timer_outq
);
ret
=
del_timer
(
&
lptr
->
device
.
timer_outq
);
//printk( "Stopped skypopen OSS driver write timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid );
printk
(
"Stopped skypopen OSS driver write timer
\n
"
);
#else// WANT_HRTIMER
ret
=
hrtimer_cancel
(
&
lptr
->
device
.
timer_inq
);
printk
(
"Stopped skypopen OSS driver read HRtimer
\n
"
);
ret
=
hrtimer_cancel
(
&
lptr
->
device
.
timer_outq
);
printk
(
"Stopped skypopen OSS driver write HRtimer
\n
"
);
#endif// WANT_HRTIMER
list_del
(
&
lptr
->
list
);
list_del
(
&
lptr
->
list
);
kfree
(
lptr
);
kfree
(
lptr
);
}
}
...
...
src/mod/endpoints/mod_skypopen/oss/skypopen.h
浏览文件 @
917879fe
...
@@ -20,6 +20,11 @@
...
@@ -20,6 +20,11 @@
#include <linux/ioctl.h>
/* needed for the _IOW etc stuff used later */
#include <linux/ioctl.h>
/* needed for the _IOW etc stuff used later */
#define SKYPOPEN_BLK 960
#define SKYPOPEN_SLEEP 10
#define CENTOS
#ifndef SKYPOPEN_MAJOR
#ifndef SKYPOPEN_MAJOR
#define SKYPOPEN_MAJOR 14
/* dynamic major by default */
#define SKYPOPEN_MAJOR 14
/* dynamic major by default */
#endif
#endif
...
@@ -28,12 +33,18 @@
...
@@ -28,12 +33,18 @@
#define SKYPOPEN_NR_DEVS 1
/* skypopen0 through skypopen3 */
#define SKYPOPEN_NR_DEVS 1
/* skypopen0 through skypopen3 */
#endif
#endif
#define WANT_HRTIMER
struct
skypopen_dev
{
struct
skypopen_dev
{
struct
cdev
cdev
;
/* Char device structure */
struct
cdev
cdev
;
/* Char device structure */
wait_queue_head_t
inq
;
/* read and write queues */
wait_queue_head_t
inq
;
/* read and write queues */
wait_queue_head_t
outq
;
/* read and write queues */
wait_queue_head_t
outq
;
/* read and write queues */
#ifndef WANT_HRTIMER
struct
timer_list
timer_inq
;
struct
timer_list
timer_inq
;
struct
timer_list
timer_outq
;
struct
timer_list
timer_outq
;
#else// WANT_HRTIMER
struct
hrtimer
timer_inq
;
struct
hrtimer
timer_outq
;
#endif// WANT_HRTIMER
int
timer_inq_started
;
int
timer_inq_started
;
int
timer_outq_started
;
int
timer_outq_started
;
};
};
...
@@ -50,11 +61,11 @@ extern int skypopen_nr_devs;
...
@@ -50,11 +61,11 @@ extern int skypopen_nr_devs;
* Prototypes for shared functions
* Prototypes for shared functions
*/
*/
ssize_t
skypopen_read
(
struct
file
*
filp
,
char
__user
*
buf
,
size_t
count
,
//
ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
loff_t
*
f_pos
);
//
loff_t *f_pos);
ssize_t
skypopen_write
(
struct
file
*
filp
,
const
char
__user
*
buf
,
size_t
count
,
//
ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
loff_t
*
f_pos
);
//
loff_t *f_pos);
int
skypopen_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
//
int skypopen_ioctl(struct inode *inode, struct file *filp,
unsigned
int
cmd
,
unsigned
long
arg
);
//
unsigned int cmd, unsigned long arg);
#endif
/* _SKYPOPEN_H_ */
#endif
/* _SKYPOPEN_H_ */
src/switch_channel.c
浏览文件 @
917879fe
...
@@ -2386,6 +2386,8 @@ SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *chann
...
@@ -2386,6 +2386,8 @@ SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *chann
{
{
switch_assert
(
channel
!=
NULL
);
switch_assert
(
channel
!=
NULL
);
switch_channel_set_flag
(
channel
,
CF_DIALPLAN
);
switch_mutex_lock
(
channel
->
profile_mutex
);
switch_mutex_lock
(
channel
->
profile_mutex
);
caller_extension
->
next
=
channel
->
caller_profile
->
caller_extension
;
caller_extension
->
next
=
channel
->
caller_profile
->
caller_extension
;
channel
->
caller_profile
->
caller_extension
=
caller_extension
;
channel
->
caller_profile
->
caller_extension
=
caller_extension
;
...
...
src/switch_core_state_machine.c
浏览文件 @
917879fe
...
@@ -123,9 +123,7 @@ static void switch_core_standard_on_routing(switch_core_session_t *session)
...
@@ -123,9 +123,7 @@ static void switch_core_standard_on_routing(switch_core_session_t *session)
}
}
}
}
if
(
count
)
{
if
(
!
count
)
{
switch_channel_set_flag
(
session
->
channel
,
CF_DIALPLAN
);
}
else
{
if
(
switch_channel_direction
(
session
->
channel
)
==
SWITCH_CALL_DIRECTION_OUTBOUND
)
{
if
(
switch_channel_direction
(
session
->
channel
)
==
SWITCH_CALL_DIRECTION_OUTBOUND
)
{
if
(
switch_channel_test_flag
(
session
->
channel
,
CF_ANSWERED
))
{
if
(
switch_channel_test_flag
(
session
->
channel
,
CF_ANSWERED
))
{
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_DEBUG
,
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_DEBUG
,
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论