Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
f65e7769
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
f65e7769
编写于
9月 06, 2005
作者:
L
Linus Torvalds
浏览文件
操作
浏览文件
下载
差异文件
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6
上级
8566cfc9
d856f1e3
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
178 addition
and
70 deletion
+178
-70
Documentation/filesystems/sysfs.txt
Documentation/filesystems/sysfs.txt
+14
-14
drivers/base/bus.c
drivers/base/bus.c
+5
-3
drivers/base/class.c
drivers/base/class.c
+33
-6
drivers/base/core.c
drivers/base/core.c
+1
-1
drivers/base/dd.c
drivers/base/dd.c
+1
-1
drivers/base/sys.c
drivers/base/sys.c
+85
-25
drivers/block/floppy.c
drivers/block/floppy.c
+28
-13
drivers/usb/core/hcd.c
drivers/usb/core/hcd.c
+1
-1
include/linux/klist.h
include/linux/klist.h
+6
-2
lib/klist.c
lib/klist.c
+4
-4
未找到文件。
Documentation/filesystems/sysfs.txt
浏览文件 @
f65e7769
...
...
@@ -90,7 +90,7 @@ void device_remove_file(struct device *, struct device_attribute *);
It also defines this helper for defining device attributes:
#define DEVICE_ATTR(_name,
_mode,_show,
_store) \
#define DEVICE_ATTR(_name,
_mode, _show,
_store) \
struct device_attribute dev_attr_##_name = { \
.attr = {.name = __stringify(_name) , .mode = _mode }, \
.show = _show, \
...
...
@@ -99,14 +99,14 @@ struct device_attribute dev_attr_##_name = { \
For example, declaring
static DEVICE_ATTR(foo,
0644,show_foo,
store_foo);
static DEVICE_ATTR(foo,
S_IWUSR | S_IRUGO, show_foo,
store_foo);
is equivalent to doing:
static struct device_attribute dev_attr_foo = {
.attr = {
.name = "foo",
.mode =
0644
,
.mode =
S_IWUSR | S_IRUGO
,
},
.show = show_foo,
.store = store_foo,
...
...
@@ -121,8 +121,8 @@ set of sysfs operations for forwarding read and write calls to the
show and store methods of the attribute owners.
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,
struct attribute *,
const char *);
ssize_t (*show)(struct kobject *, struct attribute *,
char *);
ssize_t (*store)(struct kobject *,
struct attribute *,
const char *);
};
[ Subsystems should have already defined a struct kobj_type as a
...
...
@@ -137,7 +137,7 @@ calls the associated methods.
To illustrate:
#define to_dev_attr(_attr) container_of(_attr,
struct device_attribute,
attr)
#define to_dev_attr(_attr) container_of(_attr,
struct device_attribute,
attr)
#define to_dev(d) container_of(d, struct device, kobj)
static ssize_t
...
...
@@ -148,7 +148,7 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
ssize_t ret = 0;
if (dev_attr->show)
ret = dev_attr->show(dev,buf);
ret = dev_attr->show(dev,
buf);
return ret;
}
...
...
@@ -216,16 +216,16 @@ A very simple (and naive) implementation of a device attribute is:
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%s\n",
dev->name);
return snprintf(buf, PAGE_SIZE, "%s\n",
dev->name);
}
static ssize_t store_name(struct device * dev, const char * buf)
{
sscanf(buf,
"%20s",
dev->name);
return str
len(buf
);
sscanf(buf,
"%20s",
dev->name);
return str
nlen(buf, PAGE_SIZE
);
}
static DEVICE_ATTR(name,
S_IRUGO,show_name,
store_name);
static DEVICE_ATTR(name,
S_IRUGO, show_name,
store_name);
(Note that the real implementation doesn't allow userspace to set the
...
...
@@ -290,7 +290,7 @@ struct device_attribute {
Declaring:
DEVICE_ATTR(_name,
_str,_mode,_show,
_store);
DEVICE_ATTR(_name,
_str, _mode, _show,
_store);
Creation/Removal:
...
...
@@ -310,7 +310,7 @@ struct bus_attribute {
Declaring:
BUS_ATTR(_name,
_mode,_show,
_store)
BUS_ATTR(_name,
_mode, _show,
_store)
Creation/Removal:
...
...
@@ -331,7 +331,7 @@ struct driver_attribute {
Declaring:
DRIVER_ATTR(_name,
_mode,_show,
_store)
DRIVER_ATTR(_name,
_mode, _show,
_store)
Creation/Removal:
...
...
drivers/base/bus.c
浏览文件 @
f65e7769
...
...
@@ -156,7 +156,9 @@ static ssize_t driver_unbind(struct device_driver *drv,
device_release_driver
(
dev
);
err
=
count
;
}
return
err
;
if
(
err
)
return
err
;
return
count
;
}
static
DRIVER_ATTR
(
unbind
,
S_IWUSR
,
NULL
,
driver_unbind
);
...
...
@@ -358,7 +360,7 @@ int bus_add_device(struct device * dev)
if
(
bus
)
{
pr_debug
(
"bus %s: add device %s
\n
"
,
bus
->
name
,
dev
->
bus_id
);
device_attach
(
dev
);
klist_add_tail
(
&
bus
->
klist_devices
,
&
dev
->
knode_bu
s
);
klist_add_tail
(
&
dev
->
knode_bus
,
&
bus
->
klist_device
s
);
error
=
device_add_attrs
(
bus
,
dev
);
if
(
!
error
)
{
sysfs_create_link
(
&
bus
->
devices
.
kobj
,
&
dev
->
kobj
,
dev
->
bus_id
);
...
...
@@ -446,7 +448,7 @@ int bus_add_driver(struct device_driver * drv)
}
driver_attach
(
drv
);
klist_add_tail
(
&
bus
->
klist_drivers
,
&
drv
->
knode_bu
s
);
klist_add_tail
(
&
drv
->
knode_bus
,
&
bus
->
klist_driver
s
);
module_add_driver
(
drv
->
owner
,
drv
);
driver_add_attrs
(
bus
,
drv
);
...
...
drivers/base/class.c
浏览文件 @
f65e7769
...
...
@@ -299,10 +299,8 @@ static void class_dev_release(struct kobject * kobj)
pr_debug
(
"device class '%s': release.
\n
"
,
cd
->
class_id
);
if
(
cd
->
devt_attr
)
{
kfree
(
cd
->
devt_attr
);
cd
->
devt_attr
=
NULL
;
}
kfree
(
cd
->
devt_attr
);
cd
->
devt_attr
=
NULL
;
if
(
cls
->
release
)
cls
->
release
(
cd
);
...
...
@@ -452,10 +450,29 @@ void class_device_initialize(struct class_device *class_dev)
INIT_LIST_HEAD
(
&
class_dev
->
node
);
}
static
char
*
make_class_name
(
struct
class_device
*
class_dev
)
{
char
*
name
;
int
size
;
size
=
strlen
(
class_dev
->
class
->
name
)
+
strlen
(
kobject_name
(
&
class_dev
->
kobj
))
+
2
;
name
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
!
name
)
return
ERR_PTR
(
-
ENOMEM
);
strcpy
(
name
,
class_dev
->
class
->
name
);
strcat
(
name
,
":"
);
strcat
(
name
,
kobject_name
(
&
class_dev
->
kobj
));
return
name
;
}
int
class_device_add
(
struct
class_device
*
class_dev
)
{
struct
class
*
parent
=
NULL
;
struct
class_interface
*
class_intf
;
char
*
class_name
=
NULL
;
int
error
;
class_dev
=
class_device_get
(
class_dev
);
...
...
@@ -500,9 +517,13 @@ int class_device_add(struct class_device *class_dev)
}
class_device_add_attrs
(
class_dev
);
if
(
class_dev
->
dev
)
if
(
class_dev
->
dev
)
{
class_name
=
make_class_name
(
class_dev
);
sysfs_create_link
(
&
class_dev
->
kobj
,
&
class_dev
->
dev
->
kobj
,
"device"
);
sysfs_create_link
(
&
class_dev
->
dev
->
kobj
,
&
class_dev
->
kobj
,
class_name
);
}
/* notify any interfaces this device is now here */
if
(
parent
)
{
...
...
@@ -519,6 +540,7 @@ int class_device_add(struct class_device *class_dev)
if
(
error
&&
parent
)
class_put
(
parent
);
class_device_put
(
class_dev
);
kfree
(
class_name
);
return
error
;
}
...
...
@@ -584,6 +606,7 @@ void class_device_del(struct class_device *class_dev)
{
struct
class
*
parent
=
class_dev
->
class
;
struct
class_interface
*
class_intf
;
char
*
class_name
=
NULL
;
if
(
parent
)
{
down
(
&
parent
->
sem
);
...
...
@@ -594,8 +617,11 @@ void class_device_del(struct class_device *class_dev)
up
(
&
parent
->
sem
);
}
if
(
class_dev
->
dev
)
if
(
class_dev
->
dev
)
{
class_name
=
make_class_name
(
class_dev
);
sysfs_remove_link
(
&
class_dev
->
kobj
,
"device"
);
sysfs_remove_link
(
&
class_dev
->
dev
->
kobj
,
class_name
);
}
if
(
class_dev
->
devt_attr
)
class_device_remove_file
(
class_dev
,
class_dev
->
devt_attr
);
class_device_remove_attrs
(
class_dev
);
...
...
@@ -605,6 +631,7 @@ void class_device_del(struct class_device *class_dev)
if
(
parent
)
class_put
(
parent
);
kfree
(
class_name
);
}
void
class_device_unregister
(
struct
class_device
*
class_dev
)
...
...
drivers/base/core.c
浏览文件 @
f65e7769
...
...
@@ -249,7 +249,7 @@ int device_add(struct device *dev)
if
((
error
=
bus_add_device
(
dev
)))
goto
BusError
;
if
(
parent
)
klist_add_tail
(
&
parent
->
klist_children
,
&
dev
->
knode_parent
);
klist_add_tail
(
&
dev
->
knode_parent
,
&
parent
->
klist_children
);
/* notify platform of device entry */
if
(
platform_notify
)
...
...
drivers/base/dd.c
浏览文件 @
f65e7769
...
...
@@ -42,7 +42,7 @@ void device_bind_driver(struct device * dev)
{
pr_debug
(
"bound device '%s' to driver '%s'
\n
"
,
dev
->
bus_id
,
dev
->
driver
->
name
);
klist_add_tail
(
&
dev
->
driver
->
klist_devices
,
&
dev
->
knode_driver
);
klist_add_tail
(
&
dev
->
knode_driver
,
&
dev
->
driver
->
klist_devices
);
sysfs_create_link
(
&
dev
->
driver
->
kobj
,
&
dev
->
kobj
,
kobject_name
(
&
dev
->
kobj
));
sysfs_create_link
(
&
dev
->
kobj
,
&
dev
->
driver
->
kobj
,
"driver"
);
...
...
drivers/base/sys.c
浏览文件 @
f65e7769
...
...
@@ -288,6 +288,27 @@ void sysdev_shutdown(void)
up
(
&
sysdev_drivers_lock
);
}
static
void
__sysdev_resume
(
struct
sys_device
*
dev
)
{
struct
sysdev_class
*
cls
=
dev
->
cls
;
struct
sysdev_driver
*
drv
;
/* First, call the class-specific one */
if
(
cls
->
resume
)
cls
->
resume
(
dev
);
/* Call auxillary drivers next. */
list_for_each_entry
(
drv
,
&
cls
->
drivers
,
entry
)
{
if
(
drv
->
resume
)
drv
->
resume
(
dev
);
}
/* Call global drivers. */
list_for_each_entry
(
drv
,
&
sysdev_drivers
,
entry
)
{
if
(
drv
->
resume
)
drv
->
resume
(
dev
);
}
}
/**
* sysdev_suspend - Suspend all system devices.
...
...
@@ -305,38 +326,93 @@ void sysdev_shutdown(void)
int
sysdev_suspend
(
pm_message_t
state
)
{
struct
sysdev_class
*
cls
;
struct
sys_device
*
sysdev
,
*
err_dev
;
struct
sysdev_driver
*
drv
,
*
err_drv
;
int
ret
;
pr_debug
(
"Suspending System Devices
\n
"
);
list_for_each_entry_reverse
(
cls
,
&
system_subsys
.
kset
.
list
,
kset
.
kobj
.
entry
)
{
struct
sys_device
*
sysdev
;
pr_debug
(
"Suspending type '%s':
\n
"
,
kobject_name
(
&
cls
->
kset
.
kobj
));
list_for_each_entry
(
sysdev
,
&
cls
->
kset
.
list
,
kobj
.
entry
)
{
struct
sysdev_driver
*
drv
;
pr_debug
(
" %s
\n
"
,
kobject_name
(
&
sysdev
->
kobj
));
/* Call global drivers first. */
list_for_each_entry
(
drv
,
&
sysdev_drivers
,
entry
)
{
if
(
drv
->
suspend
)
drv
->
suspend
(
sysdev
,
state
);
if
(
drv
->
suspend
)
{
ret
=
drv
->
suspend
(
sysdev
,
state
);
if
(
ret
)
goto
gbl_driver
;
}
}
/* Call auxillary drivers next. */
list_for_each_entry
(
drv
,
&
cls
->
drivers
,
entry
)
{
if
(
drv
->
suspend
)
drv
->
suspend
(
sysdev
,
state
);
if
(
drv
->
suspend
)
{
ret
=
drv
->
suspend
(
sysdev
,
state
);
if
(
ret
)
goto
aux_driver
;
}
}
/* Now call the generic one */
if
(
cls
->
suspend
)
cls
->
suspend
(
sysdev
,
state
);
if
(
cls
->
suspend
)
{
ret
=
cls
->
suspend
(
sysdev
,
state
);
if
(
ret
)
goto
cls_driver
;
}
}
}
return
0
;
/* resume current sysdev */
cls_driver:
drv
=
NULL
;
printk
(
KERN_ERR
"Class suspend failed for %s
\n
"
,
kobject_name
(
&
sysdev
->
kobj
));
aux_driver:
if
(
drv
)
printk
(
KERN_ERR
"Class driver suspend failed for %s
\n
"
,
kobject_name
(
&
sysdev
->
kobj
));
list_for_each_entry
(
err_drv
,
&
cls
->
drivers
,
entry
)
{
if
(
err_drv
==
drv
)
break
;
if
(
err_drv
->
resume
)
err_drv
->
resume
(
sysdev
);
}
drv
=
NULL
;
gbl_driver:
if
(
drv
)
printk
(
KERN_ERR
"sysdev driver suspend failed for %s
\n
"
,
kobject_name
(
&
sysdev
->
kobj
));
list_for_each_entry
(
err_drv
,
&
sysdev_drivers
,
entry
)
{
if
(
err_drv
==
drv
)
break
;
if
(
err_drv
->
resume
)
err_drv
->
resume
(
sysdev
);
}
/* resume other sysdevs in current class */
list_for_each_entry
(
err_dev
,
&
cls
->
kset
.
list
,
kobj
.
entry
)
{
if
(
err_dev
==
sysdev
)
break
;
pr_debug
(
" %s
\n
"
,
kobject_name
(
&
err_dev
->
kobj
));
__sysdev_resume
(
err_dev
);
}
/* resume other classes */
list_for_each_entry_continue
(
cls
,
&
system_subsys
.
kset
.
list
,
kset
.
kobj
.
entry
)
{
list_for_each_entry
(
err_dev
,
&
cls
->
kset
.
list
,
kobj
.
entry
)
{
pr_debug
(
" %s
\n
"
,
kobject_name
(
&
err_dev
->
kobj
));
__sysdev_resume
(
err_dev
);
}
}
return
ret
;
}
...
...
@@ -362,25 +438,9 @@ int sysdev_resume(void)
kobject_name
(
&
cls
->
kset
.
kobj
));
list_for_each_entry
(
sysdev
,
&
cls
->
kset
.
list
,
kobj
.
entry
)
{
struct
sysdev_driver
*
drv
;
pr_debug
(
" %s
\n
"
,
kobject_name
(
&
sysdev
->
kobj
));
/* First, call the class-specific one */
if
(
cls
->
resume
)
cls
->
resume
(
sysdev
);
/* Call auxillary drivers next. */
list_for_each_entry
(
drv
,
&
cls
->
drivers
,
entry
)
{
if
(
drv
->
resume
)
drv
->
resume
(
sysdev
);
}
/* Call global drivers. */
list_for_each_entry
(
drv
,
&
sysdev_drivers
,
entry
)
{
if
(
drv
->
resume
)
drv
->
resume
(
sysdev
);
}
__sysdev_resume
(
sysdev
);
}
}
return
0
;
...
...
drivers/block/floppy.c
浏览文件 @
f65e7769
...
...
@@ -493,6 +493,8 @@ static struct floppy_struct user_params[N_DRIVE];
static
sector_t
floppy_sizes
[
256
];
static
char
floppy_device_name
[]
=
"floppy"
;
/*
* The driver is trying to determine the correct media format
* while probing is set. rw_interrupt() clears it after a
...
...
@@ -4191,18 +4193,24 @@ static int __init floppy_setup(char *str)
static
int
have_no_fdc
=
-
ENODEV
;
static
ssize_t
floppy_cmos_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
platform_device
*
p
;
int
drive
;
p
=
container_of
(
dev
,
struct
platform_device
,
dev
);
drive
=
p
->
id
;
return
sprintf
(
buf
,
"%X
\n
"
,
UDP
->
cmos
);
}
DEVICE_ATTR
(
cmos
,
S_IRUGO
,
floppy_cmos_show
,
NULL
);
static
void
floppy_device_release
(
struct
device
*
dev
)
{
complete
(
&
device_release
);
}
static
struct
platform_device
floppy_device
=
{
.
name
=
"floppy"
,
.
id
=
0
,
.
dev
=
{
.
release
=
floppy_device_release
,
}
};
static
struct
platform_device
floppy_device
[
N_DRIVE
];
static
struct
kobject
*
floppy_find
(
dev_t
dev
,
int
*
part
,
void
*
data
)
{
...
...
@@ -4370,20 +4378,26 @@ static int __init floppy_init(void)
goto
out_flush_work
;
}
err
=
platform_device_register
(
&
floppy_device
);
if
(
err
)
goto
out_flush_work
;
for
(
drive
=
0
;
drive
<
N_DRIVE
;
drive
++
)
{
if
(
!
(
allowed_drive_mask
&
(
1
<<
drive
)))
continue
;
if
(
fdc_state
[
FDC
(
drive
)].
version
==
FDC_NONE
)
continue
;
floppy_device
[
drive
].
name
=
floppy_device_name
;
floppy_device
[
drive
].
id
=
drive
;
floppy_device
[
drive
].
dev
.
release
=
floppy_device_release
;
err
=
platform_device_register
(
&
floppy_device
[
drive
]);
if
(
err
)
goto
out_flush_work
;
device_create_file
(
&
floppy_device
[
drive
].
dev
,
&
dev_attr_cmos
);
/* to be cleaned up... */
disks
[
drive
]
->
private_data
=
(
void
*
)(
long
)
drive
;
disks
[
drive
]
->
queue
=
floppy_queue
;
disks
[
drive
]
->
flags
|=
GENHD_FL_REMOVABLE
;
disks
[
drive
]
->
driverfs_dev
=
&
floppy_device
.
dev
;
disks
[
drive
]
->
driverfs_dev
=
&
floppy_device
[
drive
]
.
dev
;
add_disk
(
disks
[
drive
]);
}
...
...
@@ -4603,10 +4617,11 @@ void cleanup_module(void)
fdc_state
[
FDC
(
drive
)].
version
!=
FDC_NONE
)
{
del_gendisk
(
disks
[
drive
]);
unregister_devfs_entries
(
drive
);
device_remove_file
(
&
floppy_device
[
drive
].
dev
,
&
dev_attr_cmos
);
platform_device_unregister
(
&
floppy_device
[
drive
]);
}
put_disk
(
disks
[
drive
]);
}
platform_device_unregister
(
&
floppy_device
);
devfs_remove
(
"floppy"
);
del_timer_sync
(
&
fd_timeout
);
...
...
drivers/usb/core/hcd.c
浏览文件 @
f65e7769
...
...
@@ -782,7 +782,7 @@ static int usb_register_bus(struct usb_bus *bus)
return
-
E2BIG
;
}
bus
->
class_dev
=
class_device_create
(
usb_host_class
,
MKDEV
(
0
,
0
),
bus
->
controller
,
"usb%d"
,
busnum
);
bus
->
class_dev
=
class_device_create
(
usb_host_class
,
MKDEV
(
0
,
0
),
bus
->
controller
,
"usb
_host
%d"
,
busnum
);
if
(
IS_ERR
(
bus
->
class_dev
))
{
clear_bit
(
busnum
,
busmap
.
busmap
);
up
(
&
usb_bus_list_lock
);
...
...
include/linux/klist.h
浏览文件 @
f65e7769
...
...
@@ -9,6 +9,9 @@
* This file is rleased under the GPL v2.
*/
#ifndef _LINUX_KLIST_H
#define _LINUX_KLIST_H
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/kref.h>
...
...
@@ -31,8 +34,8 @@ struct klist_node {
struct
completion
n_removed
;
};
extern
void
klist_add_tail
(
struct
klist
*
k
,
struct
klist_node
*
n
);
extern
void
klist_add_head
(
struct
klist
*
k
,
struct
klist_node
*
n
);
extern
void
klist_add_tail
(
struct
klist
_node
*
n
,
struct
klist
*
k
);
extern
void
klist_add_head
(
struct
klist
_node
*
n
,
struct
klist
*
k
);
extern
void
klist_del
(
struct
klist_node
*
n
);
extern
void
klist_remove
(
struct
klist_node
*
n
);
...
...
@@ -53,3 +56,4 @@ extern void klist_iter_init_node(struct klist * k, struct klist_iter * i,
extern
void
klist_iter_exit
(
struct
klist_iter
*
i
);
extern
struct
klist_node
*
klist_next
(
struct
klist_iter
*
i
);
#endif
lib/klist.c
浏览文件 @
f65e7769
...
...
@@ -79,11 +79,11 @@ static void klist_node_init(struct klist * k, struct klist_node * n)
/**
* klist_add_head - Initialize a klist_node and add it to front.
* @k: klist it's going on.
* @n: node we're adding.
* @k: klist it's going on.
*/
void
klist_add_head
(
struct
klist
*
k
,
struct
klist_node
*
n
)
void
klist_add_head
(
struct
klist
_node
*
n
,
struct
klist
*
k
)
{
klist_node_init
(
k
,
n
);
add_head
(
k
,
n
);
...
...
@@ -94,11 +94,11 @@ EXPORT_SYMBOL_GPL(klist_add_head);
/**
* klist_add_tail - Initialize a klist_node and add it to back.
* @k: klist it's going on.
* @n: node we're adding.
* @k: klist it's going on.
*/
void
klist_add_tail
(
struct
klist
*
k
,
struct
klist_node
*
n
)
void
klist_add_tail
(
struct
klist
_node
*
n
,
struct
klist
*
k
)
{
klist_node_init
(
k
,
n
);
add_tail
(
k
,
n
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录