Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
487680ca
Commit
487680ca
authored
Oct 17, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://ldm.bkbits.net/linux-2.5-core
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
d103bdbf
879a1092
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
466 additions
and
392 deletions
+466
-392
arch/arm/kernel/ecard.c
arch/arm/kernel/ecard.c
+1
-1
drivers/base/base.h
drivers/base/base.h
+4
-3
drivers/base/bus.c
drivers/base/bus.c
+193
-48
drivers/base/class.c
drivers/base/class.c
+96
-36
drivers/base/core.c
drivers/base/core.c
+35
-180
drivers/base/driver.c
drivers/base/driver.c
+57
-50
drivers/base/interface.c
drivers/base/interface.c
+1
-1
drivers/base/power.c
drivers/base/power.c
+31
-37
drivers/base/sys.c
drivers/base/sys.c
+4
-2
drivers/input/serio/sa1111ps2.c
drivers/input/serio/sa1111ps2.c
+1
-1
drivers/pci/pci-driver.c
drivers/pci/pci-driver.c
+1
-1
drivers/pcmcia/sa1111_generic.c
drivers/pcmcia/sa1111_generic.c
+1
-1
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_debug.c
+1
-2
drivers/scsi/sd.c
drivers/scsi/sd.c
+1
-1
drivers/scsi/sg.c
drivers/scsi/sg.c
+1
-1
drivers/scsi/sr.c
drivers/scsi/sr.c
+1
-1
drivers/scsi/st.c
drivers/scsi/st.c
+1
-1
drivers/usb/core/usb.c
drivers/usb/core/usb.c
+2
-2
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/ohci-sa1111.c
+1
-1
fs/driverfs/inode.c
fs/driverfs/inode.c
+3
-1
include/linux/device.h
include/linux/device.h
+30
-19
include/linux/driverfs_fs.h
include/linux/driverfs_fs.h
+0
-2
No files found.
arch/arm/kernel/ecard.c
View file @
487680ca
...
@@ -1114,7 +1114,7 @@ int ecard_register_driver(struct ecard_driver *drv)
...
@@ -1114,7 +1114,7 @@ int ecard_register_driver(struct ecard_driver *drv)
void
ecard_remove_driver
(
struct
ecard_driver
*
drv
)
void
ecard_remove_driver
(
struct
ecard_driver
*
drv
)
{
{
remove_driv
er
(
&
drv
->
drv
);
driver_unregist
er
(
&
drv
->
drv
);
}
}
static
int
ecard_match
(
struct
device
*
_dev
,
struct
device_driver
*
_drv
)
static
int
ecard_match
(
struct
device
*
_dev
,
struct
device_driver
*
_drv
)
...
...
drivers/base/base.h
View file @
487680ca
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
extern
struct
list_head
global_device_list
;
extern
struct
list_head
global_device_list
;
extern
spinlock_t
device_lock
;
extern
spinlock_t
device_lock
;
extern
struct
semaphore
device_sem
;
extern
struct
device
*
get_device_locked
(
struct
device
*
);
extern
struct
device
*
get_device_locked
(
struct
device
*
);
...
@@ -20,6 +21,9 @@ extern void device_remove_dir(struct device * dev);
...
@@ -20,6 +21,9 @@ extern void device_remove_dir(struct device * dev);
extern
int
bus_make_dir
(
struct
bus_type
*
bus
);
extern
int
bus_make_dir
(
struct
bus_type
*
bus
);
extern
void
bus_remove_dir
(
struct
bus_type
*
bus
);
extern
void
bus_remove_dir
(
struct
bus_type
*
bus
);
extern
int
bus_add_driver
(
struct
device_driver
*
);
extern
void
bus_remove_driver
(
struct
device_driver
*
);
extern
int
driver_make_dir
(
struct
device_driver
*
drv
);
extern
int
driver_make_dir
(
struct
device_driver
*
drv
);
extern
void
driver_remove_dir
(
struct
device_driver
*
drv
);
extern
void
driver_remove_dir
(
struct
device_driver
*
drv
);
...
@@ -48,9 +52,6 @@ extern int interface_add(struct device_class *, struct device *);
...
@@ -48,9 +52,6 @@ extern int interface_add(struct device_class *, struct device *);
extern
void
interface_remove
(
struct
device_class
*
,
struct
device
*
);
extern
void
interface_remove
(
struct
device_class
*
,
struct
device
*
);
extern
int
driver_attach
(
struct
device_driver
*
drv
);
extern
void
driver_detach
(
struct
device_driver
*
drv
);
#ifdef CONFIG_HOTPLUG
#ifdef CONFIG_HOTPLUG
extern
int
dev_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
extern
int
dev_hotplug
(
struct
device
*
dev
,
const
char
*
action
);
#else
#else
...
...
drivers/base/bus.c
View file @
487680ca
...
@@ -43,28 +43,23 @@ int bus_for_each_dev(struct bus_type * bus, void * data,
...
@@ -43,28 +43,23 @@ int bus_for_each_dev(struct bus_type * bus, void * data,
int
(
*
callback
)(
struct
device
*
dev
,
void
*
data
))
int
(
*
callback
)(
struct
device
*
dev
,
void
*
data
))
{
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
device
*
prev
=
NULL
;
int
error
=
0
;
int
error
=
0
;
get_bus
(
bus
);
bus
=
get_bus
(
bus
);
spin_lock
(
&
device_lock
);
if
(
bus
)
{
list_for_each
(
node
,
&
bus
->
devices
)
{
down_read
(
&
bus
->
rwsem
);
struct
device
*
dev
=
get_device_locked
(
to_dev
(
node
));
list_for_each
(
node
,
&
bus
->
devices
)
{
if
(
dev
)
{
struct
device
*
dev
=
get_device
(
to_dev
(
node
));
spin_unlock
(
&
device_lock
);
if
(
dev
)
{
error
=
callback
(
dev
,
data
);
error
=
callback
(
dev
,
data
);
if
(
prev
)
put_device
(
dev
);
put_device
(
prev
);
if
(
error
)
prev
=
dev
;
break
;
spin_lock
(
&
device_lock
);
}
if
(
error
)
break
;
}
}
up_read
(
&
bus
->
rwsem
);
put_bus
(
bus
);
}
}
spin_unlock
(
&
device_lock
);
if
(
prev
)
put_device
(
prev
);
put_bus
(
bus
);
return
error
;
return
error
;
}
}
...
@@ -72,33 +67,126 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
...
@@ -72,33 +67,126 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
int
(
*
callback
)(
struct
device_driver
*
drv
,
void
*
data
))
int
(
*
callback
)(
struct
device_driver
*
drv
,
void
*
data
))
{
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
device_driver
*
prev
=
NULL
;
int
error
=
0
;
int
error
=
0
;
/* pin bus in memory */
bus
=
get_bus
(
bus
);
get_bus
(
bus
);
if
(
bus
)
{
down_read
(
&
bus
->
rwsem
);
list_for_each
(
node
,
&
bus
->
drivers
)
{
struct
device_driver
*
drv
=
get_driver
(
to_drv
(
node
));
if
(
drv
)
{
error
=
callback
(
drv
,
data
);
put_driver
(
drv
);
if
(
error
)
break
;
}
}
up_read
(
&
bus
->
rwsem
);
put_bus
(
bus
);
}
return
error
;
}
spin_lock
(
&
device_lock
);
static
void
attach
(
struct
device
*
dev
)
list_for_each
(
node
,
&
bus
->
drivers
)
{
{
struct
device_driver
*
drv
=
get_driver
(
to_drv
(
node
));
pr_debug
(
"bound device '%s' to driver '%s'
\n
"
,
if
(
drv
)
{
dev
->
bus_id
,
dev
->
driver
->
name
);
spin_unlock
(
&
device_lock
);
list_add_tail
(
&
dev
->
driver_list
,
&
dev
->
driver
->
devices
);
error
=
callback
(
drv
,
data
);
}
if
(
prev
)
put_driver
(
prev
);
static
int
bus_match
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
prev
=
drv
;
{
spin_lock
(
&
device_lock
);
int
error
=
0
;
if
(
error
)
if
(
dev
->
bus
->
match
(
dev
,
drv
))
{
break
;
dev
->
driver
=
drv
;
if
(
drv
->
probe
)
{
if
(
!
(
error
=
drv
->
probe
(
dev
)))
attach
(
dev
);
else
dev
->
driver
=
NULL
;
}
}
}
}
spin_unlock
(
&
device_lock
);
if
(
prev
)
put_driver
(
prev
);
put_bus
(
bus
);
return
error
;
return
error
;
}
}
static
int
device_attach
(
struct
device
*
dev
)
{
struct
bus_type
*
bus
=
dev
->
bus
;
struct
list_head
*
entry
;
int
error
=
0
;
if
(
dev
->
driver
)
{
attach
(
dev
);
return
0
;
}
if
(
!
bus
->
match
)
return
0
;
list_for_each
(
entry
,
&
bus
->
drivers
)
{
struct
device_driver
*
drv
=
get_driver
(
container_of
(
entry
,
struct
device_driver
,
bus_list
));
if
(
!
drv
)
continue
;
error
=
bus_match
(
dev
,
drv
);
put_driver
(
drv
);
if
(
!
error
)
break
;
}
return
error
;
}
static
int
driver_attach
(
struct
device_driver
*
drv
)
{
struct
bus_type
*
bus
=
drv
->
bus
;
struct
list_head
*
entry
;
int
error
=
0
;
if
(
!
bus
->
match
)
return
0
;
list_for_each
(
entry
,
&
bus
->
devices
)
{
struct
device
*
dev
=
container_of
(
entry
,
struct
device
,
bus_list
);
if
(
get_device
(
dev
))
{
if
(
!
dev
->
driver
)
{
if
(
!
bus_match
(
dev
,
drv
)
&&
dev
->
driver
)
devclass_add_device
(
dev
);
}
put_device
(
dev
);
}
}
return
error
;
}
static
void
detach
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
{
if
(
drv
)
{
list_del_init
(
&
dev
->
driver_list
);
devclass_remove_device
(
dev
);
if
(
drv
->
remove
)
drv
->
remove
(
dev
);
dev
->
driver
=
NULL
;
}
}
static
void
device_detach
(
struct
device
*
dev
)
{
detach
(
dev
,
dev
->
driver
);
}
static
void
driver_detach
(
struct
device_driver
*
drv
)
{
struct
list_head
*
entry
,
*
next
;
list_for_each_safe
(
entry
,
next
,
&
drv
->
devices
)
{
struct
device
*
dev
=
container_of
(
entry
,
struct
device
,
driver_list
);
if
(
get_device
(
dev
))
{
detach
(
dev
,
drv
);
put_device
(
dev
);
}
}
}
/**
/**
* bus_add_device - add device to bus
* bus_add_device - add device to bus
* @dev: device being added
* @dev: device being added
...
@@ -110,12 +198,13 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
...
@@ -110,12 +198,13 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
*/
*/
int
bus_add_device
(
struct
device
*
dev
)
int
bus_add_device
(
struct
device
*
dev
)
{
{
if
(
dev
->
bus
)
{
struct
bus_type
*
bus
=
get_bus
(
dev
->
bus
);
pr_debug
(
"registering %s with bus '%s'
\n
"
,
dev
->
bus_id
,
dev
->
bus
->
name
);
if
(
bus
)
{
get_bus
(
dev
->
bus
);
down_write
(
&
dev
->
bus
->
rwsem
);
spin_lock
(
&
device_lock
);
pr_debug
(
"bus %s: add device %s
\n
"
,
bus
->
name
,
dev
->
bus_id
);
list_add_tail
(
&
dev
->
bus_list
,
&
dev
->
bus
->
devices
);
list_add_tail
(
&
dev
->
bus_list
,
&
dev
->
bus
->
devices
);
spin_unlock
(
&
device_lock
);
device_attach
(
dev
);
up_write
(
&
dev
->
bus
->
rwsem
);
device_bus_link
(
dev
);
device_bus_link
(
dev
);
}
}
return
0
;
return
0
;
...
@@ -131,17 +220,70 @@ int bus_add_device(struct device * dev)
...
@@ -131,17 +220,70 @@ int bus_add_device(struct device * dev)
void
bus_remove_device
(
struct
device
*
dev
)
void
bus_remove_device
(
struct
device
*
dev
)
{
{
if
(
dev
->
bus
)
{
if
(
dev
->
bus
)
{
down_write
(
&
dev
->
bus
->
rwsem
);
pr_debug
(
"bus %s: remove device %s
\n
"
,
dev
->
bus
->
name
,
dev
->
bus_id
);
device_remove_symlink
(
&
dev
->
bus
->
device_dir
,
dev
->
bus_id
);
device_remove_symlink
(
&
dev
->
bus
->
device_dir
,
dev
->
bus_id
);
device_detach
(
dev
);
list_del_init
(
&
dev
->
bus_list
);
up_write
(
&
dev
->
bus
->
rwsem
);
put_bus
(
dev
->
bus
);
put_bus
(
dev
->
bus
);
}
}
}
}
int
bus_add_driver
(
struct
device_driver
*
drv
)
{
struct
bus_type
*
bus
=
get_bus
(
drv
->
bus
);
if
(
bus
)
{
down_write
(
&
bus
->
rwsem
);
pr_debug
(
"bus %s: add driver %s
\n
"
,
bus
->
name
,
drv
->
name
);
list_add_tail
(
&
drv
->
bus_list
,
&
bus
->
drivers
);
driver_attach
(
drv
);
up_write
(
&
bus
->
rwsem
);
driver_make_dir
(
drv
);
}
return
0
;
}
void
bus_remove_driver
(
struct
device_driver
*
drv
)
{
if
(
drv
->
bus
)
{
down_write
(
&
drv
->
bus
->
rwsem
);
pr_debug
(
"bus %s: remove driver %s
\n
"
,
drv
->
bus
->
name
,
drv
->
name
);
driver_detach
(
drv
);
list_del_init
(
&
drv
->
bus_list
);
up_write
(
&
drv
->
bus
->
rwsem
);
}
}
struct
bus_type
*
get_bus
(
struct
bus_type
*
bus
)
{
struct
bus_type
*
ret
=
bus
;
spin_lock
(
&
device_lock
);
if
(
bus
&&
bus
->
present
&&
atomic_read
(
&
bus
->
refcount
))
atomic_inc
(
&
bus
->
refcount
);
else
ret
=
NULL
;
spin_unlock
(
&
device_lock
);
return
ret
;
}
void
put_bus
(
struct
bus_type
*
bus
)
{
if
(
!
atomic_dec_and_lock
(
&
bus
->
refcount
,
&
device_lock
))
return
;
list_del_init
(
&
bus
->
node
);
spin_unlock
(
&
device_lock
);
BUG_ON
(
bus
->
present
);
bus_remove_dir
(
bus
);
}
int
bus_register
(
struct
bus_type
*
bus
)
int
bus_register
(
struct
bus_type
*
bus
)
{
{
rwlock_init
(
&
bus
->
lock
);
init_rwsem
(
&
bus
->
rwsem
);
INIT_LIST_HEAD
(
&
bus
->
devices
);
INIT_LIST_HEAD
(
&
bus
->
devices
);
INIT_LIST_HEAD
(
&
bus
->
drivers
);
INIT_LIST_HEAD
(
&
bus
->
drivers
);
atomic_set
(
&
bus
->
refcount
,
2
);
atomic_set
(
&
bus
->
refcount
,
2
);
bus
->
present
=
1
;
spin_lock
(
&
device_lock
);
spin_lock
(
&
device_lock
);
list_add_tail
(
&
bus
->
node
,
&
bus_driver_list
);
list_add_tail
(
&
bus
->
node
,
&
bus_driver_list
);
...
@@ -156,13 +298,14 @@ int bus_register(struct bus_type * bus)
...
@@ -156,13 +298,14 @@ int bus_register(struct bus_type * bus)
return
0
;
return
0
;
}
}
void
put_bus
(
struct
bus_type
*
bus
)
void
bus_unregister
(
struct
bus_type
*
bus
)
{
{
if
(
!
atomic_dec_and_lock
(
&
bus
->
refcount
,
&
device_lock
))
spin_lock
(
&
device_lock
);
return
;
bus
->
present
=
0
;
list_del_init
(
&
bus
->
node
);
spin_unlock
(
&
device_lock
);
spin_unlock
(
&
device_lock
);
bus_remove_dir
(
bus
);
pr_debug
(
"bus %s: unregistering
\n
"
,
bus
->
name
);
put_bus
(
bus
);
}
}
EXPORT_SYMBOL
(
bus_for_each_dev
);
EXPORT_SYMBOL
(
bus_for_each_dev
);
...
@@ -170,4 +313,6 @@ EXPORT_SYMBOL(bus_for_each_drv);
...
@@ -170,4 +313,6 @@ EXPORT_SYMBOL(bus_for_each_drv);
EXPORT_SYMBOL
(
bus_add_device
);
EXPORT_SYMBOL
(
bus_add_device
);
EXPORT_SYMBOL
(
bus_remove_device
);
EXPORT_SYMBOL
(
bus_remove_device
);
EXPORT_SYMBOL
(
bus_register
);
EXPORT_SYMBOL
(
bus_register
);
EXPORT_SYMBOL
(
bus_unregister
);
EXPORT_SYMBOL
(
get_bus
);
EXPORT_SYMBOL
(
put_bus
);
EXPORT_SYMBOL
(
put_bus
);
drivers/base/class.c
View file @
487680ca
...
@@ -10,27 +10,29 @@ static LIST_HEAD(class_list);
...
@@ -10,27 +10,29 @@ static LIST_HEAD(class_list);
int
devclass_add_driver
(
struct
device_driver
*
drv
)
int
devclass_add_driver
(
struct
device_driver
*
drv
)
{
{
if
(
drv
->
devclass
)
{
struct
device_class
*
cls
=
get_devclass
(
drv
->
devclass
);
pr_debug
(
"Registering driver %s:%s with class %s
\n
"
,
if
(
cls
)
{
drv
->
bus
->
name
,
drv
->
name
,
drv
->
devclass
->
name
);
down_write
(
&
cls
->
rwsem
);
pr_debug
(
"device class %s: adding driver %s:%s
\n
"
,
spin_lock
(
&
device_lock
);
cls
->
name
,
drv
->
bus
->
name
,
drv
->
name
);
list_add_tail
(
&
drv
->
class_list
,
&
drv
->
devclass
->
drivers
);
list_add_tail
(
&
drv
->
class_list
,
&
cls
->
drivers
);
spin_unlock
(
&
device_lock
);
devclass_drv_link
(
drv
);
devclass_drv_link
(
drv
);
up_write
(
&
cls
->
rwsem
);
}
}
return
0
;
return
0
;
}
}
void
devclass_remove_driver
(
struct
device_driver
*
drv
)
void
devclass_remove_driver
(
struct
device_driver
*
drv
)
{
{
if
(
drv
->
devclass
)
{
struct
device_class
*
cls
=
drv
->
devclass
;
pr_debug
(
"Removing driver %s:%s:%s
\n
"
,
if
(
cls
)
{
drv
->
devclass
->
name
,
drv
->
bus
->
name
,
drv
->
name
);
down_write
(
&
cls
->
rwsem
);
spin_lock
(
&
device_lock
);
pr_debug
(
"device class %s: removing driver %s:%s
\n
"
,
cls
->
name
,
drv
->
bus
->
name
,
drv
->
name
);
list_del_init
(
&
drv
->
class_list
);
list_del_init
(
&
drv
->
class_list
);
spin_unlock
(
&
device_lock
);
devclass_drv_unlink
(
drv
);
devclass_drv_unlink
(
drv
);
up_write
(
&
cls
->
rwsem
);
put_devclass
(
cls
);
}
}
}
}
...
@@ -38,9 +40,7 @@ void devclass_remove_driver(struct device_driver * drv)
...
@@ -38,9 +40,7 @@ void devclass_remove_driver(struct device_driver * drv)
static
void
enum_device
(
struct
device_class
*
cls
,
struct
device
*
dev
)
static
void
enum_device
(
struct
device_class
*
cls
,
struct
device
*
dev
)
{
{
u32
val
;
u32
val
;
spin_lock
(
&
device_lock
);
val
=
cls
->
devnum
++
;
val
=
cls
->
devnum
++
;
spin_unlock
(
&
device_lock
);
dev
->
class_num
=
val
;
dev
->
class_num
=
val
;
devclass_dev_link
(
cls
,
dev
);
devclass_dev_link
(
cls
,
dev
);
}
}
...
@@ -51,18 +51,44 @@ static void unenum_device(struct device_class * cls, struct device * dev)
...
@@ -51,18 +51,44 @@ static void unenum_device(struct device_class * cls, struct device * dev)
dev
->
class_num
=
0
;
dev
->
class_num
=
0
;
}
}
/**
* devclass_add_device - register device with device class
* @dev: device to be registered
*
* This is called when a device is either registered with the
* core, or after the a driver module is loaded and bound to
* the device.
* The class is determined by looking at @dev's driver, so one
* way or another, it must be bound to something. Once the
* class is determined, it's set to prevent against concurrent
* calls for the same device stomping on each other.
*
* /sbin/hotplug should be called once the device is added to
* class and all the interfaces.
*/
int
devclass_add_device
(
struct
device
*
dev
)
int
devclass_add_device
(
struct
device
*
dev
)
{
{
struct
device_class
*
cls
=
dev
->
driver
->
devclass
;
struct
device_class
*
cls
;
int
error
=
0
;
int
error
=
0
;
if
(
cls
)
{
pr_debug
(
"adding device '%s' to class '%s'
\n
"
,
if
(
dev
->
driver
)
{
dev
->
name
,
cls
->
name
);
cls
=
get_devclass
(
dev
->
driver
->
devclass
);
if
(
cls
->
add_device
)
if
(
cls
)
{
error
=
cls
->
add_device
(
dev
);
down_write
(
&
cls
->
rwsem
);
if
(
!
error
)
{
pr_debug
(
"device class %s: adding device %s
\n
"
,
enum_device
(
cls
,
dev
);
cls
->
name
,
dev
->
name
);
interface_add
(
cls
,
dev
);
if
(
cls
->
add_device
)
error
=
cls
->
add_device
(
dev
);
if
(
!
error
)
{
enum_device
(
cls
,
dev
);
interface_add
(
cls
,
dev
);
}
/* notify userspace (call /sbin/hotplug) here */
up_write
(
&
cls
->
rwsem
);
if
(
error
)
put_devclass
(
cls
);
}
}
}
}
return
error
;
return
error
;
...
@@ -70,40 +96,74 @@ int devclass_add_device(struct device * dev)
...
@@ -70,40 +96,74 @@ int devclass_add_device(struct device * dev)
void
devclass_remove_device
(
struct
device
*
dev
)
void
devclass_remove_device
(
struct
device
*
dev
)
{
{
struct
device_class
*
cls
=
dev
->
driver
->
devclass
;
struct
device_class
*
cls
;
if
(
cls
)
{
pr_debug
(
"removing device '%s' from class '%s'
\n
"
,
if
(
dev
->
driver
)
{
dev
->
name
,
cls
->
name
);
cls
=
dev
->
driver
->
devclass
;
interface_remove
(
cls
,
dev
);
if
(
cls
)
{
unenum_device
(
cls
,
dev
);
down_write
(
&
cls
->
rwsem
);
if
(
cls
->
remove_device
)
pr_debug
(
"device class %s: removing device %s
\n
"
,
cls
->
remove_device
(
dev
);
cls
->
name
,
dev
->
name
);
interface_remove
(
cls
,
dev
);
unenum_device
(
cls
,
dev
);
if
(
cls
->
remove_device
)
cls
->
remove_device
(
dev
);
up_write
(
&
cls
->
rwsem
);
put_devclass
(
cls
);
}
}
}
}
}
struct
device_class
*
get_devclass
(
struct
device_class
*
cls
)
{
struct
device_class
*
ret
=
cls
;
spin_lock
(
&
device_lock
);
if
(
cls
&&
cls
->
present
&&
atomic_read
(
&
cls
->
refcount
)
>
0
)
atomic_inc
(
&
cls
->
refcount
);
else
ret
=
NULL
;
spin_unlock
(
&
device_lock
);
return
ret
;
}
void
put_devclass
(
struct
device_class
*
cls
)
{
if
(
atomic_dec_and_lock
(
&
cls
->
refcount
,
&
device_lock
))
{
list_del_init
(
&
cls
->
node
);
spin_unlock
(
&
device_lock
);
devclass_remove_dir
(
cls
);
}
}
int
devclass_register
(
struct
device_class
*
cls
)
int
devclass_register
(
struct
device_class
*
cls
)
{
{
INIT_LIST_HEAD
(
&
cls
->
drivers
);
INIT_LIST_HEAD
(
&
cls
->
drivers
);
INIT_LIST_HEAD
(
&
cls
->
intf_list
);
INIT_LIST_HEAD
(
&
cls
->
intf_list
);
init_rwsem
(
&
cls
->
rwsem
);
pr_debug
(
"registering device class '%s'
\n
"
,
cls
->
name
);
atomic_set
(
&
cls
->
refcount
,
2
);
cls
->
present
=
1
;
pr_debug
(
"device class '%s': registering
\n
"
,
cls
->
name
);
spin_lock
(
&
device_lock
);
spin_lock
(
&
device_lock
);
list_add_tail
(
&
cls
->
node
,
&
class_list
);
list_add_tail
(
&
cls
->
node
,
&
class_list
);
spin_unlock
(
&
device_lock
);
spin_unlock
(
&
device_lock
);
devclass_make_dir
(
cls
);
devclass_make_dir
(
cls
);
put_devclass
(
cls
);
return
0
;
return
0
;
}
}
void
devclass_unregister
(
struct
device_class
*
cls
)
void
devclass_unregister
(
struct
device_class
*
cls
)
{
{
pr_debug
(
"unregistering device class '%s'
\n
"
,
cls
->
name
);
devclass_remove_dir
(
cls
);
spin_lock
(
&
device_lock
);
spin_lock
(
&
device_lock
);
list_del_init
(
&
class_list
)
;
cls
->
present
=
0
;
spin_unlock
(
&
device_lock
);
spin_unlock
(
&
device_lock
);
pr_debug
(
"device class '%s': unregistering
\n
"
,
cls
->
name
);
put_devclass
(
cls
);
}
}
EXPORT_SYMBOL
(
devclass_register
);
EXPORT_SYMBOL
(
devclass_register
);
EXPORT_SYMBOL
(
devclass_unregister
);
EXPORT_SYMBOL
(
devclass_unregister
);
EXPORT_SYMBOL
(
get_devclass
);
EXPORT_SYMBOL
(
put_devclass
);
drivers/base/core.c
View file @
487680ca
...
@@ -19,136 +19,12 @@ LIST_HEAD(global_device_list);
...
@@ -19,136 +19,12 @@ LIST_HEAD(global_device_list);
int
(
*
platform_notify
)(
struct
device
*
dev
)
=
NULL
;
int
(
*
platform_notify
)(
struct
device
*
dev
)
=
NULL
;
int
(
*
platform_notify_remove
)(
struct
device
*
dev
)
=
NULL
;
int
(
*
platform_notify_remove
)(
struct
device
*
dev
)
=
NULL
;
DECLARE_MUTEX
(
device_sem
);
spinlock_t
device_lock
=
SPIN_LOCK_UNLOCKED
;
spinlock_t
device_lock
=
SPIN_LOCK_UNLOCKED
;
#define to_dev(node) container_of(node,struct device,driver_list)
#define to_dev(node) container_of(node,struct device,driver_list)
static
int
probe
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
{
dev
->
driver
=
drv
;
return
drv
->
probe
?
drv
->
probe
(
dev
)
:
0
;
}
static
void
attach
(
struct
device
*
dev
)
{
spin_lock
(
&
device_lock
);
list_add_tail
(
&
dev
->
driver_list
,
&
dev
->
driver
->
devices
);
spin_unlock
(
&
device_lock
);
devclass_add_device
(
dev
);
}
/**
* found_match - do actual binding of device to driver
* @dev: device
* @drv: driver
*
* We're here because the bus's match callback returned success for this
* pair. We call the driver's probe callback to verify they're really a
* match made in heaven.
*
* In the future, we may want to notify userspace of the binding. (But,
* we might not want to do it here).
*
* We may also want to create a symlink in the driver's directory to the
* device's physical directory.
*/
static
int
found_match
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
{
int
error
=
0
;
if
(
!
(
error
=
probe
(
dev
,
get_driver
(
drv
))))
{
pr_debug
(
"bound device '%s' to driver '%s'
\n
"
,
dev
->
bus_id
,
drv
->
name
);
attach
(
dev
);
}
else
{
put_driver
(
drv
);
dev
->
driver
=
NULL
;
}
return
error
;
}
/**
* device_attach - try to associated device with a driver
* @drv: current driver to try
* @data: device in disguise
*
* This function is used as a callback to bus_for_each_drv.
* It calls the bus's match callback to check if the driver supports
* the device. If so, it calls the found_match() function above to
* take care of all the details.
*/
static
int
do_device_attach
(
struct
device_driver
*
drv
,
void
*
data
)
{
struct
device
*
dev
=
(
struct
device
*
)
data
;
int
error
=
0
;
if
(
drv
->
bus
->
match
&&
drv
->
bus
->
match
(
dev
,
drv
))
error
=
found_match
(
dev
,
drv
);
return
error
;
}
static
int
device_attach
(
struct
device
*
dev
)
{
int
error
=
0
;
if
(
!
dev
->
driver
)
{
if
(
dev
->
bus
)
error
=
bus_for_each_drv
(
dev
->
bus
,
dev
,
do_device_attach
);
}
else
attach
(
dev
);
return
error
;
}
static
void
device_detach
(
struct
device
*
dev
)
{
struct
device_driver
*
drv
=
dev
->
driver
;
if
(
drv
)
{
devclass_remove_device
(
dev
);
if
(
drv
&&
drv
->
remove
)
drv
->
remove
(
dev
);
dev
->
driver
=
NULL
;
}
}
static
int
do_driver_attach
(
struct
device
*
dev
,
void
*
data
)
{
struct
device_driver
*
drv
=
(
struct
device_driver
*
)
data
;
int
error
=
0
;
if
(
!
dev
->
driver
)
{
if
(
dev
->
bus
->
match
&&
dev
->
bus
->
match
(
dev
,
drv
))
error
=
found_match
(
dev
,
drv
);
}
return
error
;
}
int
driver_attach
(
struct
device_driver
*
drv
)
{
return
bus_for_each_dev
(
drv
->
bus
,
drv
,
do_driver_attach
);
}
void
driver_detach
(
struct
device_driver
*
drv
)
{
struct
list_head
*
node
;
struct
device
*
prev
=
NULL
;
spin_lock
(
&
device_lock
);
list_for_each
(
node
,
&
drv
->
devices
)
{
struct
device
*
dev
=
get_device_locked
(
to_dev
(
node
));
if
(
dev
)
{
if
(
prev
)
list_del_init
(
&
prev
->
driver_list
);
spin_unlock
(
&
device_lock
);
device_detach
(
dev
);
if
(
prev
)
put_device
(
prev
);
prev
=
dev
;
spin_lock
(
&
device_lock
);
}
}
spin_unlock
(
&
device_lock
);
}
int
device_add
(
struct
device
*
dev
)
int
device_add
(
struct
device
*
dev
)
{
{
int
error
;
int
error
;
...
@@ -156,14 +32,14 @@ int device_add(struct device *dev)
...
@@ -156,14 +32,14 @@ int device_add(struct device *dev)
if
(
!
dev
||
!
strlen
(
dev
->
bus_id
))
if
(
!
dev
||
!
strlen
(
dev
->
bus_id
))
return
-
EINVAL
;
return
-
EINVAL
;
spin_lock
(
&
device_lock
);
down
(
&
device_sem
);
dev
->
present
=
1
;
dev
->
state
=
DEVICE_REGISTERED
;
if
(
dev
->
parent
)
{
if
(
dev
->
parent
)
{
list_add_tail
(
&
dev
->
g_list
,
&
dev
->
parent
->
g_list
);
list_add_tail
(
&
dev
->
g_list
,
&
dev
->
parent
->
g_list
);
list_add_tail
(
&
dev
->
node
,
&
dev
->
parent
->
children
);
list_add_tail
(
&
dev
->
node
,
&
dev
->
parent
->
children
);
}
else
}
else
list_add_tail
(
&
dev
->
g_list
,
&
global_device_list
);
list_add_tail
(
&
dev
->
g_list
,
&
global_device_list
);
spin_unlock
(
&
device_lock
);
up
(
&
device_sem
);
pr_debug
(
"DEV: registering device: ID = '%s', name = %s
\n
"
,
pr_debug
(
"DEV: registering device: ID = '%s', name = %s
\n
"
,
dev
->
bus_id
,
dev
->
name
);
dev
->
bus_id
,
dev
->
name
);
...
@@ -173,9 +49,6 @@ int device_add(struct device *dev)
...
@@ -173,9 +49,6 @@ int device_add(struct device *dev)
bus_add_device
(
dev
);
bus_add_device
(
dev
);
/* bind to driver */
device_attach
(
dev
);
/* notify platform of device entry */
/* notify platform of device entry */
if
(
platform_notify
)
if
(
platform_notify
)
platform_notify
(
dev
);
platform_notify
(
dev
);
...
@@ -183,12 +56,13 @@ int device_add(struct device *dev)
...
@@ -183,12 +56,13 @@ int device_add(struct device *dev)
/* notify userspace of device entry */
/* notify userspace of device entry */
dev_hotplug
(
dev
,
"add"
);
dev_hotplug
(
dev
,
"add"
);
devclass_add_device
(
dev
);
register_done:
register_done:
if
(
error
)
{
if
(
error
)
{
spin_lock
(
&
device_lock
);
up
(
&
device_sem
);
list_del_init
(
&
dev
->
g_list
);
list_del_init
(
&
dev
->
g_list
);
list_del_init
(
&
dev
->
node
);
list_del_init
(
&
dev
->
node
);
spin_unlock
(
&
device_lock
);
up
(
&
device_sem
);
}
}
return
error
;
return
error
;
}
}
...
@@ -203,6 +77,7 @@ void device_initialize(struct device *dev)
...
@@ -203,6 +77,7 @@ void device_initialize(struct device *dev)
INIT_LIST_HEAD
(
&
dev
->
intf_list
);
INIT_LIST_HEAD
(
&
dev
->
intf_list
);
spin_lock_init
(
&
dev
->
lock
);
spin_lock_init
(
&
dev
->
lock
);
atomic_set
(
&
dev
->
refcount
,
1
);
atomic_set
(
&
dev
->
refcount
,
1
);
dev
->
state
=
DEVICE_INITIALIZED
;
if
(
dev
->
parent
)
if
(
dev
->
parent
)
get_device
(
dev
->
parent
);
get_device
(
dev
->
parent
);
}
}
...
@@ -234,22 +109,15 @@ int device_register(struct device *dev)
...
@@ -234,22 +109,15 @@ int device_register(struct device *dev)
return
error
;
return
error
;
}
}
struct
device
*
get_device
_locked
(
struct
device
*
dev
)
struct
device
*
get_device
(
struct
device
*
dev
)
{
{
struct
device
*
ret
=
dev
;
struct
device
*
ret
=
dev
;
if
(
dev
&&
dev
->
present
&&
atomic_read
(
&
dev
->
refcount
)
>
0
)
down
(
&
device_sem
);
if
(
device_present
(
dev
)
&&
atomic_read
(
&
dev
->
refcount
)
>
0
)
atomic_inc
(
&
dev
->
refcount
);
atomic_inc
(
&
dev
->
refcount
);
else
else
ret
=
NULL
;
ret
=
NULL
;
return
ret
;
up
(
&
device_sem
);
}
struct
device
*
get_device
(
struct
device
*
dev
)
{
struct
device
*
ret
;
spin_lock
(
&
device_lock
);
ret
=
get_device_locked
(
dev
);
spin_unlock
(
&
device_lock
);
return
ret
;
return
ret
;
}
}
...
@@ -259,34 +127,23 @@ struct device * get_device(struct device * dev)
...
@@ -259,34 +127,23 @@ struct device * get_device(struct device * dev)
*/
*/
void
put_device
(
struct
device
*
dev
)
void
put_device
(
struct
device
*
dev
)
{
{
struct
device
*
parent
;
down
(
&
device_sem
);
if
(
!
atomic_dec_and_lock
(
&
dev
->
refcount
,
&
device_lock
))
if
(
!
atomic_dec_and_test
(
&
dev
->
refcount
))
{
up
(
&
device_sem
);
return
;
return
;
parent
=
dev
->
parent
;
}
dev
->
parent
=
NULL
;
list_del_init
(
&
dev
->
node
);
spin_unlock
(
&
device_lock
);
list_del_init
(
&
dev
->
g_list
);
up
(
&
device_sem
);
BUG_ON
(
dev
->
present
);
BUG_ON
(
(
dev
->
state
!=
DEVICE_GONE
)
);
if
(
dev
->
release
)
device_del
(
dev
);
dev
->
release
(
dev
);
if
(
parent
)
put_device
(
parent
);
}
}
void
device_del
(
struct
device
*
dev
)
void
device_del
(
struct
device
*
dev
)
{
{
spin_lock
(
&
device_lock
);
struct
device
*
parent
=
dev
->
parent
;
dev
->
present
=
0
;
list_del_init
(
&
dev
->
node
);
list_del_init
(
&
dev
->
g_list
);
list_del_init
(
&
dev
->
bus_list
);
list_del_init
(
&
dev
->
driver_list
);
spin_unlock
(
&
device_lock
);
pr_debug
(
"DEV: Unregistering device. ID = '%s', name = '%s'
\n
"
,
dev
->
bus_id
,
dev
->
name
);
/* Notify the platform of the removal, in case they
/* Notify the platform of the removal, in case they
* need to do anything...
* need to do anything...
...
@@ -297,11 +154,16 @@ void device_del(struct device * dev)
...
@@ -297,11 +154,16 @@ void device_del(struct device * dev)
/* notify userspace that this device is about to disappear */
/* notify userspace that this device is about to disappear */
dev_hotplug
(
dev
,
"remove"
);
dev_hotplug
(
dev
,
"remove"
);
device_detach
(
dev
);
bus_remove_device
(
dev
);
bus_remove_device
(
dev
);
/* remove the driverfs directory */
/* remove the driverfs directory */
device_remove_dir
(
dev
);
device_remove_dir
(
dev
);
if
(
dev
->
release
)
dev
->
release
(
dev
);
if
(
parent
)
put_device
(
parent
);
}
}
/**
/**
...
@@ -315,22 +177,15 @@ void device_del(struct device * dev)
...
@@ -315,22 +177,15 @@ void device_del(struct device * dev)
*/
*/
void
device_unregister
(
struct
device
*
dev
)
void
device_unregister
(
struct
device
*
dev
)
{
{
device_del
(
dev
);
down
(
&
device_sem
);
put_device
(
dev
);
dev
->
state
=
DEVICE_GONE
;
}
up
(
&
device_sem
);
static
int
__init
device_init
(
void
)
{
int
error
;
error
=
init_driverfs_fs
();
pr_debug
(
"DEV: Unregistering device. ID = '%s', name = '%s'
\n
"
,
if
(
error
)
dev
->
bus_id
,
dev
->
name
);
panic
(
"DEV: could not initialize driverfs"
);
put_device
(
dev
);
return
0
;
}
}
core_initcall
(
device_init
);
EXPORT_SYMBOL
(
device_register
);
EXPORT_SYMBOL
(
device_register
);
EXPORT_SYMBOL
(
device_unregister
);
EXPORT_SYMBOL
(
device_unregister
);
EXPORT_SYMBOL
(
get_device
);
EXPORT_SYMBOL
(
get_device
);
...
...
drivers/base/driver.c
View file @
487680ca
...
@@ -16,29 +16,61 @@ int driver_for_each_dev(struct device_driver * drv, void * data,
...
@@ -16,29 +16,61 @@ int driver_for_each_dev(struct device_driver * drv, void * data,
int
(
*
callback
)(
struct
device
*
,
void
*
))
int
(
*
callback
)(
struct
device
*
,
void
*
))
{
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
device
*
prev
=
NULL
;
int
error
=
0
;
int
error
=
0
;
get_driver
(
drv
);
drv
=
get_driver
(
drv
);
spin_lock
(
&
device_lock
);
if
(
drv
)
{
list_for_each
(
node
,
&
drv
->
devices
)
{
down_read
(
&
drv
->
bus
->
rwsem
);
struct
device
*
dev
=
get_device_locked
(
to_dev
(
node
));
list_for_each
(
node
,
&
drv
->
devices
)
{
if
(
dev
)
{
struct
device
*
dev
=
get_device
(
to_dev
(
node
));
spin_unlock
(
&
device_lock
);
if
(
dev
)
{
error
=
callback
(
dev
,
data
);
error
=
callback
(
dev
,
data
);
if
(
prev
)
put_device
(
dev
);
put_device
(
prev
);
if
(
error
)
prev
=
dev
;
break
;
spin_lock
(
&
device_lock
);
}
if
(
error
)
break
;
}
}
up_read
(
&
drv
->
bus
->
rwsem
);
put_driver
(
drv
);
}
}
spin_unlock
(
&
device_lock
);
put_driver
(
drv
);
return
error
;
return
error
;
}
}
struct
device_driver
*
get_driver
(
struct
device_driver
*
drv
)
{
struct
device_driver
*
ret
=
drv
;
spin_lock
(
&
device_lock
);
if
(
drv
&&
drv
->
present
&&
atomic_read
(
&
drv
->
refcount
)
>
0
)
atomic_inc
(
&
drv
->
refcount
);
else
ret
=
NULL
;
spin_unlock
(
&
device_lock
);
return
ret
;
}
void
remove_driver
(
struct
device_driver
*
drv
)
{
BUG
();
}
/**
* put_driver - decrement driver's refcount and clean up if necessary
* @drv: driver in question
*/
void
put_driver
(
struct
device_driver
*
drv
)
{
struct
bus_type
*
bus
=
drv
->
bus
;
if
(
!
atomic_dec_and_lock
(
&
drv
->
refcount
,
&
device_lock
))
return
;
spin_unlock
(
&
device_lock
);
BUG_ON
(
drv
->
present
);
bus_remove_driver
(
drv
);
if
(
drv
->
release
)
drv
->
release
(
drv
);
put_bus
(
bus
);
}
/**
/**
* driver_register - register driver with bus
* driver_register - register driver with bus
* @drv: driver to register
* @drv: driver to register
...
@@ -50,54 +82,29 @@ int driver_register(struct device_driver * drv)
...
@@ -50,54 +82,29 @@ int driver_register(struct device_driver * drv)
if
(
!
drv
->
bus
)
if
(
!
drv
->
bus
)
return
-
EINVAL
;
return
-
EINVAL
;
pr_debug
(
"
Registering driver '%s' with bus '%s'
\n
"
,
drv
->
name
,
drv
->
bus
->
name
);
pr_debug
(
"
driver %s:%s: registering
\n
"
,
drv
->
bus
->
name
,
drv
->
name
);
get_bus
(
drv
->
bus
);
get_bus
(
drv
->
bus
);
atomic_set
(
&
drv
->
refcount
,
2
);
atomic_set
(
&
drv
->
refcount
,
2
);
rwlock_init
(
&
drv
->
lock
);
rwlock_init
(
&
drv
->
lock
);
INIT_LIST_HEAD
(
&
drv
->
devices
);
INIT_LIST_HEAD
(
&
drv
->
devices
);
spin_lock
(
&
device_lock
);
drv
->
present
=
1
;
list_add
(
&
drv
->
bus_list
,
&
drv
->
bus
->
drivers
);
bus_add_driver
(
drv
);
spin_unlock
(
&
device_lock
);
driver_make_dir
(
drv
);
driver_attach
(
drv
);
put_driver
(
drv
);
put_driver
(
drv
);
return
0
;
return
0
;
}
}
static
void
__remove_driver
(
struct
device_driver
*
drv
)
void
driver_unregister
(
struct
device_driver
*
drv
)
{
pr_debug
(
"Unregistering driver '%s' from bus '%s'
\n
"
,
drv
->
name
,
drv
->
bus
->
name
);
driver_detach
(
drv
);
driver_remove_dir
(
drv
);
if
(
drv
->
release
)
drv
->
release
(
drv
);
put_bus
(
drv
->
bus
);
}
void
remove_driver
(
struct
device_driver
*
drv
)
{
{
spin_lock
(
&
device_lock
);
spin_lock
(
&
device_lock
);
atomic_set
(
&
drv
->
refcount
,
0
);
drv
->
present
=
0
;
list_del_init
(
&
drv
->
bus_list
);
spin_unlock
(
&
device_lock
);
spin_unlock
(
&
device_lock
);
__remove_driver
(
drv
);
pr_debug
(
"driver %s:%s: unregistering
\n
"
,
drv
->
bus
->
name
,
drv
->
name
);
}
put_driver
(
drv
);
/**
* put_driver - decrement driver's refcount and clean up if necessary
* @drv: driver in question
*/
void
put_driver
(
struct
device_driver
*
drv
)
{
if
(
!
atomic_dec_and_lock
(
&
drv
->
refcount
,
&
device_lock
))
return
;
list_del_init
(
&
drv
->
bus_list
);
spin_unlock
(
&
device_lock
);
__remove_driver
(
drv
);
}
}
EXPORT_SYMBOL
(
driver_for_each_dev
);
EXPORT_SYMBOL
(
driver_for_each_dev
);
EXPORT_SYMBOL
(
driver_register
);
EXPORT_SYMBOL
(
driver_register
);
EXPORT_SYMBOL
(
driver_unregister
);
EXPORT_SYMBOL
(
get_driver
);
EXPORT_SYMBOL
(
put_driver
);
EXPORT_SYMBOL
(
put_driver
);
EXPORT_SYMBOL
(
remove_driver
);
drivers/base/interface.c
View file @
487680ca
...
@@ -19,7 +19,7 @@ static DEVICE_ATTR(name,S_IRUGO,device_read_name,NULL);
...
@@ -19,7 +19,7 @@ static DEVICE_ATTR(name,S_IRUGO,device_read_name,NULL);
static
ssize_t
static
ssize_t
device_read_power
(
struct
device
*
dev
,
char
*
page
,
size_t
count
,
loff_t
off
)
device_read_power
(
struct
device
*
dev
,
char
*
page
,
size_t
count
,
loff_t
off
)
{
{
return
off
?
0
:
sprintf
(
page
,
"%d
\n
"
,
dev
->
current
_state
);
return
off
?
0
:
sprintf
(
page
,
"%d
\n
"
,
dev
->
power
_state
);
}
}
static
ssize_t
static
ssize_t
...
...
drivers/base/power.c
View file @
487680ca
...
@@ -8,6 +8,8 @@
...
@@ -8,6 +8,8 @@
*
*
*/
*/
#define DEBUG 0
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
#include "base.h"
#include "base.h"
...
@@ -28,34 +30,21 @@
...
@@ -28,34 +30,21 @@
int
device_suspend
(
u32
state
,
u32
level
)
int
device_suspend
(
u32
state
,
u32
level
)
{
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
device
*
prev
=
NULL
;
int
error
=
0
;
int
error
=
0
;
if
(
level
==
SUSPEND_POWER_DOWN
)
printk
(
KERN_EMERG
"Suspending devices
\n
"
);
printk
(
KERN_EMERG
"Shutting down devices
\n
"
);
else
printk
(
KERN_EMERG
"Suspending devices
\n
"
);
spin_lock
(
&
device_lock
);
down
(
&
device_sem
);
list_for_each
(
node
,
&
global_device_list
)
{
list_for_each
(
node
,
&
global_device_list
)
{
struct
device
*
dev
=
get_device_locked
(
to_dev
(
node
));
struct
device
*
dev
=
to_dev
(
node
);
if
(
dev
)
{
if
(
device_present
(
dev
)
&&
dev
->
driver
&&
dev
->
driver
->
suspend
)
{
spin_unlock
(
&
device_lock
);
pr_debug
(
"suspending device %s
\n
"
,
dev
->
name
);
if
(
dev
->
driver
)
{
error
=
dev
->
driver
->
suspend
(
dev
,
state
,
level
);
if
(
level
==
SUSPEND_POWER_DOWN
)
{
if
(
error
)
if
(
dev
->
driver
->
remove
)
printk
(
KERN_ERR
"%s: suspend returned %d
\n
"
,
dev
->
name
,
error
);
dev
->
driver
->
remove
(
dev
);
}
else
if
(
dev
->
driver
->
suspend
)
error
=
dev
->
driver
->
suspend
(
dev
,
state
,
level
);
}
if
(
prev
)
put_device
(
prev
);
prev
=
dev
;
spin_lock
(
&
device_lock
);
}
}
}
}
spin_unlock
(
&
device_lock
);
up
(
&
device_sem
);
return
error
;
return
error
;
}
}
...
@@ -70,33 +59,38 @@ int device_suspend(u32 state, u32 level)
...
@@ -70,33 +59,38 @@ int device_suspend(u32 state, u32 level)
void
device_resume
(
u32
level
)
void
device_resume
(
u32
level
)
{
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
device
*
prev
=
NULL
;
spin_lock
(
&
device_lock
);
down
(
&
device_sem
);
list_for_each_prev
(
node
,
&
global_device_list
)
{
list_for_each_prev
(
node
,
&
global_device_list
)
{
struct
device
*
dev
=
get_device_locked
(
to_dev
(
node
));
struct
device
*
dev
=
to_dev
(
node
);
if
(
dev
)
{
if
(
device_present
(
dev
)
&&
dev
->
driver
&&
dev
->
driver
->
resume
)
{
spin_unlock
(
&
device_lock
);
pr_debug
(
"resuming device %s
\n
"
,
dev
->
name
);
if
(
dev
->
driver
&&
dev
->
driver
->
resume
)
dev
->
driver
->
resume
(
dev
,
level
);
dev
->
driver
->
resume
(
dev
,
level
);
if
(
prev
)
put_device
(
prev
);
prev
=
dev
;
spin_lock
(
&
device_lock
);
}
}
}
}
spin_unlock
(
&
device_lock
);
up
(
&
device_sem
);
printk
(
KERN_EMERG
"Devices Resumed
\n
"
);
printk
(
KERN_EMERG
"Devices Resumed
\n
"
);
}
}
/**
/**
* device_shutdown - call device_suspend with status set to shutdown, to
* device_shutdown - call ->remove() on each device to shutdown.
* cause all devices to remove themselves cleanly
*/
*/
void
device_shutdown
(
void
)
void
device_shutdown
(
void
)
{
{
device_suspend
(
4
,
SUSPEND_POWER_DOWN
);
struct
list_head
*
entry
;
printk
(
KERN_EMERG
"Shutting down devices
\n
"
);
down
(
&
device_sem
);
list_for_each
(
entry
,
&
global_device_list
)
{
struct
device
*
dev
=
to_dev
(
entry
);
if
(
device_present
(
dev
)
&&
dev
->
driver
&&
dev
->
driver
->
shutdown
)
{
pr_debug
(
"shutting down %s
\n
"
,
dev
->
name
);
dev
->
driver
->
shutdown
(
dev
);
}
}
up
(
&
device_sem
);
}
}
EXPORT_SYMBOL
(
device_suspend
);
EXPORT_SYMBOL
(
device_suspend
);
...
...
drivers/base/sys.c
View file @
487680ca
...
@@ -10,6 +10,8 @@
...
@@ -10,6 +10,8 @@
* add themselves as children of the system bus.
* add themselves as children of the system bus.
*/
*/
#define DEBUG 1
#include <linux/device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
...
@@ -76,8 +78,8 @@ int sys_register_root(struct sys_root * root)
...
@@ -76,8 +78,8 @@ int sys_register_root(struct sys_root * root)
*/
*/
void
sys_unegister_root
(
struct
sys_root
*
root
)
void
sys_unegister_root
(
struct
sys_root
*
root
)
{
{
put_device
(
&
root
->
sysdev
);
device_unregister
(
&
root
->
sysdev
);
put_device
(
&
root
->
dev
);
device_unregister
(
&
root
->
dev
);
}
}
/**
/**
...
...
drivers/input/serio/sa1111ps2.c
View file @
487680ca
...
@@ -354,7 +354,7 @@ static int __init ps2_init(void)
...
@@ -354,7 +354,7 @@ static int __init ps2_init(void)
static
void
__exit
ps2_exit
(
void
)
static
void
__exit
ps2_exit
(
void
)
{
{
remove_driv
er
(
&
ps2_driver
.
drv
);
driver_unregist
er
(
&
ps2_driver
.
drv
);
}
}
module_init
(
ps2_init
);
module_init
(
ps2_init
);
...
...
drivers/pci/pci-driver.c
View file @
487680ca
...
@@ -141,7 +141,7 @@ pci_register_driver(struct pci_driver *drv)
...
@@ -141,7 +141,7 @@ pci_register_driver(struct pci_driver *drv)
void
void
pci_unregister_driver
(
struct
pci_driver
*
drv
)
pci_unregister_driver
(
struct
pci_driver
*
drv
)
{
{
remove_driv
er
(
&
drv
->
driver
);
driver_unregist
er
(
&
drv
->
driver
);
}
}
static
struct
pci_driver
pci_compat_driver
=
{
static
struct
pci_driver
pci_compat_driver
=
{
...
...
drivers/pcmcia/sa1111_generic.c
View file @
487680ca
...
@@ -297,7 +297,7 @@ static int __init sa1111_drv_pcmcia_init(void)
...
@@ -297,7 +297,7 @@ static int __init sa1111_drv_pcmcia_init(void)
static
void
__exit
sa1111_drv_pcmcia_exit
(
void
)
static
void
__exit
sa1111_drv_pcmcia_exit
(
void
)
{
{
remove_driv
er
(
&
pcmcia_driver
.
drv
);
driver_unregist
er
(
&
pcmcia_driver
.
drv
);
}
}
module_init
(
sa1111_drv_pcmcia_init
);
module_init
(
sa1111_drv_pcmcia_init
);
...
...
drivers/scsi/scsi_debug.c
View file @
487680ca
...
@@ -861,8 +861,7 @@ static int scsi_debug_release(struct Scsi_Host * hpnt)
...
@@ -861,8 +861,7 @@ static int scsi_debug_release(struct Scsi_Host * hpnt)
if
(
++
num_releases
==
num_present
)
{
if
(
++
num_releases
==
num_present
)
{
#ifdef DRIVERFS_SUPPORT
#ifdef DRIVERFS_SUPPORT
do_remove_driverfs_files
();
do_remove_driverfs_files
();
remove_driver
(
&
sdebug_driverfs_driver
);
driver_unregister
(
&
sdebug_driverfs_driver
);
// driver_unregister(&sdebug_driverfs_driver);
#endif
#endif
vfree
(
fake_storep
);
vfree
(
fake_storep
);
vfree
(
devInfop
);
vfree
(
devInfop
);
...
...
drivers/scsi/sd.c
View file @
487680ca
...
@@ -1525,7 +1525,7 @@ static void __exit exit_sd(void)
...
@@ -1525,7 +1525,7 @@ static void __exit exit_sd(void)
vfree
(
sd_dsk_arr
);
vfree
(
sd_dsk_arr
);
}
}
sd_template
.
dev_max
=
0
;
sd_template
.
dev_max
=
0
;
remove_driv
er
(
&
sd_template
.
scsi_driverfs_driver
);
driver_unregist
er
(
&
sd_template
.
scsi_driverfs_driver
);
unregister_reboot_notifier
(
&
sd_notifier_block
);
unregister_reboot_notifier
(
&
sd_notifier_block
);
}
}
...
...
drivers/scsi/sg.c
View file @
487680ca
...
@@ -1655,7 +1655,7 @@ exit_sg(void)
...
@@ -1655,7 +1655,7 @@ exit_sg(void)
sg_dev_arr
=
NULL
;
sg_dev_arr
=
NULL
;
}
}
sg_template
.
dev_max
=
0
;
sg_template
.
dev_max
=
0
;
remove_driv
er
(
&
sg_template
.
scsi_driverfs_driver
);
driver_unregist
er
(
&
sg_template
.
scsi_driverfs_driver
);
}
}
static
int
static
int
...
...
drivers/scsi/sr.c
View file @
487680ca
...
@@ -856,7 +856,7 @@ static void __exit exit_sr(void)
...
@@ -856,7 +856,7 @@ static void __exit exit_sr(void)
kfree
(
scsi_CDs
);
kfree
(
scsi_CDs
);
sr_template
.
dev_max
=
0
;
sr_template
.
dev_max
=
0
;
remove_driv
er
(
&
sr_template
.
scsi_driverfs_driver
);
driver_unregist
er
(
&
sr_template
.
scsi_driverfs_driver
);
}
}
module_init
(
init_sr
);
module_init
(
init_sr
);
...
...
drivers/scsi/st.c
View file @
487680ca
...
@@ -3992,7 +3992,7 @@ static void __exit exit_st(void)
...
@@ -3992,7 +3992,7 @@ static void __exit exit_st(void)
kfree
(
scsi_tapes
);
kfree
(
scsi_tapes
);
}
}
st_template
.
dev_max
=
0
;
st_template
.
dev_max
=
0
;
remove_driv
er
(
&
st_template
.
scsi_driverfs_driver
);
driver_unregist
er
(
&
st_template
.
scsi_driverfs_driver
);
printk
(
KERN_INFO
"st: Unloaded.
\n
"
);
printk
(
KERN_INFO
"st: Unloaded.
\n
"
);
}
}
...
...
drivers/usb/core/usb.c
View file @
487680ca
...
@@ -208,7 +208,7 @@ void usb_deregister(struct usb_driver *driver)
...
@@ -208,7 +208,7 @@ void usb_deregister(struct usb_driver *driver)
{
{
info
(
"deregistering driver %s"
,
driver
->
name
);
info
(
"deregistering driver %s"
,
driver
->
name
);
remove_driv
er
(
&
driver
->
driver
);
driver_unregist
er
(
&
driver
->
driver
);
usbfs_update_special
();
usbfs_update_special
();
}
}
...
@@ -1394,7 +1394,7 @@ static void __exit usb_exit(void)
...
@@ -1394,7 +1394,7 @@ static void __exit usb_exit(void)
if
(
nousb
)
if
(
nousb
)
return
;
return
;
remove_driv
er
(
&
usb_generic_driver
);
driver_unregist
er
(
&
usb_generic_driver
);
usb_major_cleanup
();
usb_major_cleanup
();
usbfs_cleanup
();
usbfs_cleanup
();
usb_hub_cleanup
();
usb_hub_cleanup
();
...
...
drivers/usb/host/ohci-sa1111.c
View file @
487680ca
...
@@ -413,7 +413,7 @@ static int __init ohci_hcd_sa1111_init (void)
...
@@ -413,7 +413,7 @@ static int __init ohci_hcd_sa1111_init (void)
static
void
__exit
ohci_hcd_sa1111_cleanup
(
void
)
static
void
__exit
ohci_hcd_sa1111_cleanup
(
void
)
{
{
remove_driv
er
(
&
ohci_hcd_sa1111_driver
.
drv
);
driver_unregist
er
(
&
ohci_hcd_sa1111_driver
.
drv
);
}
}
module_init
(
ohci_hcd_sa1111_init
);
module_init
(
ohci_hcd_sa1111_init
);
...
...
fs/driverfs/inode.c
View file @
487680ca
...
@@ -509,11 +509,13 @@ static void put_mount(void)
...
@@ -509,11 +509,13 @@ static void put_mount(void)
DBG
(
"driverfs: mount_count = %d
\n
"
,
mount_count
);
DBG
(
"driverfs: mount_count = %d
\n
"
,
mount_count
);
}
}
int
__init
init_driverfs_fs
(
void
)
static
int
__init
driverfs_init
(
void
)
{
{
return
register_filesystem
(
&
driverfs_fs_type
);
return
register_filesystem
(
&
driverfs_fs_type
);
}
}
core_initcall
(
driverfs_init
);
static
struct
dentry
*
get_dentry
(
struct
dentry
*
parent
,
const
char
*
name
)
static
struct
dentry
*
get_dentry
(
struct
dentry
*
parent
,
const
char
*
name
)
{
{
struct
qstr
qstr
;
struct
qstr
qstr
;
...
...
include/linux/device.h
View file @
487680ca
...
@@ -48,14 +48,22 @@ enum {
...
@@ -48,14 +48,22 @@ enum {
RESUME_ENABLE
,
RESUME_ENABLE
,
};
};
enum
device_state
{
DEVICE_UNINITIALIZED
=
0
,
DEVICE_INITIALIZED
=
1
,
DEVICE_REGISTERED
=
2
,
DEVICE_GONE
=
3
,
};
struct
device
;
struct
device
;
struct
device_driver
;
struct
device_driver
;
struct
device_class
;
struct
device_class
;
struct
bus_type
{
struct
bus_type
{
char
*
name
;
char
*
name
;
rwlock_t
lock
;
struct
rw_semaphore
rwsem
;
atomic_t
refcount
;
atomic_t
refcount
;
u32
present
;
struct
list_head
node
;
struct
list_head
node
;
struct
list_head
devices
;
struct
list_head
devices
;
...
@@ -73,14 +81,9 @@ struct bus_type {
...
@@ -73,14 +81,9 @@ struct bus_type {
extern
int
bus_register
(
struct
bus_type
*
bus
);
extern
int
bus_register
(
struct
bus_type
*
bus
);
extern
void
bus_unregister
(
struct
bus_type
*
bus
);
static
inline
struct
bus_type
*
get_bus
(
struct
bus_type
*
bus
)
extern
struct
bus_type
*
get_bus
(
struct
bus_type
*
bus
);
{
BUG_ON
(
!
atomic_read
(
&
bus
->
refcount
));
atomic_inc
(
&
bus
->
refcount
);
return
bus
;
}
extern
void
put_bus
(
struct
bus_type
*
bus
);
extern
void
put_bus
(
struct
bus_type
*
bus
);
extern
int
bus_for_each_dev
(
struct
bus_type
*
bus
,
void
*
data
,
extern
int
bus_for_each_dev
(
struct
bus_type
*
bus
,
void
*
data
,
...
@@ -114,6 +117,7 @@ struct device_driver {
...
@@ -114,6 +117,7 @@ struct device_driver {
rwlock_t
lock
;
rwlock_t
lock
;
atomic_t
refcount
;
atomic_t
refcount
;
u32
present
;
struct
list_head
bus_list
;
struct
list_head
bus_list
;
struct
list_head
class_list
;
struct
list_head
class_list
;
...
@@ -123,7 +127,7 @@ struct device_driver {
...
@@ -123,7 +127,7 @@ struct device_driver {
int
(
*
probe
)
(
struct
device
*
dev
);
int
(
*
probe
)
(
struct
device
*
dev
);
int
(
*
remove
)
(
struct
device
*
dev
);
int
(
*
remove
)
(
struct
device
*
dev
);
void
(
*
shutdown
)
(
struct
device
*
dev
);
int
(
*
suspend
)
(
struct
device
*
dev
,
u32
state
,
u32
level
);
int
(
*
suspend
)
(
struct
device
*
dev
,
u32
state
,
u32
level
);
int
(
*
resume
)
(
struct
device
*
dev
,
u32
level
);
int
(
*
resume
)
(
struct
device
*
dev
,
u32
level
);
...
@@ -131,16 +135,10 @@ struct device_driver {
...
@@ -131,16 +135,10 @@ struct device_driver {
};
};
extern
int
driver_register
(
struct
device_driver
*
drv
);
extern
int
driver_register
(
struct
device_driver
*
drv
);
extern
void
driver_unregister
(
struct
device_driver
*
drv
);
static
inline
struct
device_driver
*
get_driver
(
struct
device_driver
*
drv
)
extern
struct
device_driver
*
get_driver
(
struct
device_driver
*
drv
);
{
BUG_ON
(
!
atomic_read
(
&
drv
->
refcount
));
atomic_inc
(
&
drv
->
refcount
);
return
drv
;
}
extern
void
put_driver
(
struct
device_driver
*
drv
);
extern
void
put_driver
(
struct
device_driver
*
drv
);
extern
void
remove_driver
(
struct
device_driver
*
drv
);
extern
void
remove_driver
(
struct
device_driver
*
drv
);
...
@@ -172,6 +170,11 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
...
@@ -172,6 +170,11 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
*/
*/
struct
device_class
{
struct
device_class
{
char
*
name
;
char
*
name
;
struct
rw_semaphore
rwsem
;
atomic_t
refcount
;
u32
present
;
u32
devnum
;
u32
devnum
;
struct
list_head
node
;
struct
list_head
node
;
...
@@ -189,6 +192,9 @@ struct device_class {
...
@@ -189,6 +192,9 @@ struct device_class {
extern
int
devclass_register
(
struct
device_class
*
);
extern
int
devclass_register
(
struct
device_class
*
);
extern
void
devclass_unregister
(
struct
device_class
*
);
extern
void
devclass_unregister
(
struct
device_class
*
);
extern
struct
device_class
*
get_devclass
(
struct
device_class
*
);
extern
void
put_devclass
(
struct
device_class
*
);
struct
devclass_attribute
{
struct
devclass_attribute
{
struct
attribute
attr
;
struct
attribute
attr
;
...
@@ -289,8 +295,8 @@ struct device {
...
@@ -289,8 +295,8 @@ struct device {
void
*
platform_data
;
/* Platform specific data (e.g. ACPI,
void
*
platform_data
;
/* Platform specific data (e.g. ACPI,
BIOS data relevant to device) */
BIOS data relevant to device) */
u32
present
;
enum
device_state
state
;
u32
current
_state
;
/* Current operating state. In
u32
power
_state
;
/* Current operating state. In
ACPI-speak, this is D0-D3, D0
ACPI-speak, this is D0-D3, D0
being fully functional, and D3
being fully functional, and D3
being off. */
being off. */
...
@@ -362,6 +368,11 @@ extern int (*platform_notify)(struct device * dev);
...
@@ -362,6 +368,11 @@ extern int (*platform_notify)(struct device * dev);
extern
int
(
*
platform_notify_remove
)(
struct
device
*
dev
);
extern
int
(
*
platform_notify_remove
)(
struct
device
*
dev
);
static
inline
int
device_present
(
struct
device
*
dev
)
{
return
(
dev
&&
(
dev
->
state
==
DEVICE_INITIALIZED
||
dev
->
state
==
DEVICE_REGISTERED
));
}
/* device and bus locking helpers.
/* device and bus locking helpers.
*
*
* FIXME: Is there anything else we need to do?
* FIXME: Is there anything else we need to do?
...
...
include/linux/driverfs_fs.h
View file @
487680ca
...
@@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent,
...
@@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent,
extern
void
extern
void
driverfs_remove_file
(
struct
driver_dir_entry
*
,
const
char
*
name
);
driverfs_remove_file
(
struct
driver_dir_entry
*
,
const
char
*
name
);
extern
int
init_driverfs_fs
(
void
);
#endif
/* _DDFS_H_ */
#endif
/* _DDFS_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment