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
f4ad044b
Commit
f4ad044b
authored
May 29, 2002
by
Patrick Mochel
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://linux.bkbits.net/linux-2.5
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-linus
parents
ca980f75
44729bba
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
253 additions
and
112 deletions
+253
-112
drivers/base/base.h
drivers/base/base.h
+3
-0
drivers/base/bus.c
drivers/base/bus.c
+87
-0
drivers/base/core.c
drivers/base/core.c
+118
-7
drivers/base/driver.c
drivers/base/driver.c
+2
-0
drivers/pci/hotplug.c
drivers/pci/hotplug.c
+3
-31
drivers/pci/pci-driver.c
drivers/pci/pci-driver.c
+32
-73
include/linux/device.h
include/linux/device.h
+8
-1
No files found.
drivers/base/base.h
View file @
f4ad044b
...
...
@@ -17,3 +17,6 @@ extern int device_make_dir(struct device * dev);
extern
void
device_remove_dir
(
struct
device
*
dev
);
extern
int
device_bus_link
(
struct
device
*
dev
);
extern
int
driver_bind
(
struct
device_driver
*
drv
);
extern
void
driver_unbind
(
struct
device_driver
*
drv
);
drivers/base/bus.c
View file @
f4ad044b
...
...
@@ -22,6 +22,91 @@ static struct driver_dir_entry bus_dir = {
mode:
(
S_IFDIR
|
S_IRWXU
|
S_IRUGO
|
S_IXUGO
),
};
/**
* bus_for_each_dev - walk list of devices and do something to each
* @bus: bus in question
* @data: data for the callback
* @callback: caller-defined action to perform on each device
*
* Why do we do this? So we can guarantee proper locking and reference
* counting on devices as we touch each one.
*
* Algorithm:
* Take the bus lock and get the first node in the list. We increment
* the reference count and unlock the bus. If we have a device from a
* previous iteration, we decrement the reference count.
* After we call the callback, we get the next node in the list and loop.
* At the end, if @dev is not null, we still have it pinned, so we need
* to let it go.
*/
int
bus_for_each_dev
(
struct
bus_type
*
bus
,
void
*
data
,
int
(
*
callback
)(
struct
device
*
dev
,
void
*
data
))
{
struct
device
*
next
;
struct
device
*
dev
=
NULL
;
struct
list_head
*
node
;
int
error
=
0
;
get_bus
(
bus
);
read_lock
(
&
bus
->
lock
);
node
=
bus
->
devices
.
next
;
while
(
node
!=
&
bus
->
devices
)
{
next
=
list_entry
(
node
,
struct
device
,
bus_list
);
get_device
(
next
);
read_unlock
(
&
bus
->
lock
);
if
(
dev
)
put_device
(
dev
);
dev
=
next
;
if
((
error
=
callback
(
dev
,
data
)))
{
put_device
(
dev
);
break
;
}
read_lock
(
&
bus
->
lock
);
node
=
dev
->
bus_list
.
next
;
}
read_unlock
(
&
bus
->
lock
);
if
(
dev
)
put_device
(
dev
);
put_bus
(
bus
);
return
error
;
}
int
bus_for_each_drv
(
struct
bus_type
*
bus
,
void
*
data
,
int
(
*
callback
)(
struct
device_driver
*
drv
,
void
*
data
))
{
struct
device_driver
*
next
;
struct
device_driver
*
drv
=
NULL
;
struct
list_head
*
node
;
int
error
=
0
;
/* pin bus in memory */
get_bus
(
bus
);
read_lock
(
&
bus
->
lock
);
node
=
bus
->
drivers
.
next
;
while
(
node
!=
&
bus
->
drivers
)
{
next
=
list_entry
(
node
,
struct
device_driver
,
bus_list
);
get_driver
(
next
);
read_unlock
(
&
bus
->
lock
);
if
(
drv
)
put_driver
(
drv
);
drv
=
next
;
if
((
error
=
callback
(
drv
,
data
)))
{
put_driver
(
drv
);
break
;
}
read_lock
(
&
bus
->
lock
);
node
=
drv
->
bus_list
.
next
;
}
read_unlock
(
&
bus
->
lock
);
if
(
drv
)
put_driver
(
drv
);
put_bus
(
bus
);
return
error
;
}
/**
* bus_add_device - add device to bus
* @dev: device being added
...
...
@@ -119,6 +204,8 @@ static int __init bus_init(void)
core_initcall
(
bus_init
);
EXPORT_SYMBOL
(
bus_for_each_dev
);
EXPORT_SYMBOL
(
bus_for_each_drv
);
EXPORT_SYMBOL
(
bus_add_device
);
EXPORT_SYMBOL
(
bus_remove_device
);
EXPORT_SYMBOL
(
bus_register
);
...
...
drivers/base/core.c
View file @
f4ad044b
...
...
@@ -23,6 +23,120 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
spinlock_t
device_lock
=
SPIN_LOCK_UNLOCKED
;
/**
* found_match - do actual binding of device to driver
* @dev: device
* @drv: driver
*
* We're here because the bus's bind 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
;
dev
->
driver
=
get_driver
(
drv
);
if
(
drv
->
probe
)
if
(
drv
->
probe
(
dev
))
goto
ProbeFailed
;
pr_debug
(
"bound device '%s' to driver '%s'
\n
"
,
dev
->
bus_id
,
drv
->
name
);
write_lock
(
&
drv
->
lock
);
list_add_tail
(
&
dev
->
driver_list
,
&
drv
->
devices
);
write_unlock
(
&
drv
->
lock
);
goto
Done
;
ProbeFailed:
put_driver
(
drv
);
dev
->
driver
=
NULL
;
Done:
return
error
;
}
/**
* bind_device - 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 ::bind 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_bind
(
struct
device_driver
*
drv
,
void
*
data
)
{
struct
device
*
dev
=
(
struct
device
*
)
data
;
int
error
=
0
;
if
(
!
dev
->
driver
)
{
if
(
drv
->
bus
->
bind
&&
drv
->
bus
->
bind
(
dev
,
drv
))
error
=
found_match
(
dev
,
drv
);
}
return
error
;
}
static
int
device_bind
(
struct
device
*
dev
)
{
int
error
=
0
;
if
(
dev
->
bus
)
error
=
bus_for_each_drv
(
dev
->
bus
,
dev
,
do_device_bind
);
return
error
;
}
static
void
device_unbind
(
struct
device
*
dev
)
{
/* unbind from driver */
if
(
dev
->
driver
&&
dev
->
driver
->
remove
)
dev
->
driver
->
remove
(
dev
,
REMOVE_NOTIFY
);
}
static
int
do_driver_bind
(
struct
device
*
dev
,
void
*
data
)
{
struct
device_driver
*
drv
=
(
struct
device_driver
*
)
data
;
int
error
=
0
;
if
(
!
dev
->
driver
)
{
if
(
dev
->
bus
->
bind
&&
dev
->
bus
->
bind
(
dev
,
drv
))
error
=
found_match
(
dev
,
drv
);
}
return
error
;
}
int
driver_bind
(
struct
device_driver
*
drv
)
{
return
bus_for_each_dev
(
drv
->
bus
,
drv
,
do_driver_bind
);
}
static
int
do_driver_unbind
(
struct
device
*
dev
,
void
*
data
)
{
struct
device_driver
*
drv
=
(
struct
device_driver
*
)
data
;
lock_device
(
dev
);
if
(
dev
->
driver
==
drv
)
{
dev
->
driver
=
NULL
;
unlock_device
(
dev
);
if
(
drv
->
remove
)
drv
->
remove
(
dev
,
REMOVE_NOTIFY
);
}
else
unlock_device
(
dev
);
return
0
;
}
void
driver_unbind
(
struct
device_driver
*
drv
)
{
// driver_for_each_dev(drv,drv,do_driver_unbind);
}
/**
* device_register - register a device
* @dev: pointer to the device structure
...
...
@@ -72,6 +186,9 @@ int device_register(struct device *dev)
bus_add_device
(
dev
);
/* bind to driver */
device_bind
(
dev
);
/* notify platform of device entry */
if
(
platform_notify
)
platform_notify
(
dev
);
...
...
@@ -104,15 +221,9 @@ void put_device(struct device * dev)
if
(
platform_notify_remove
)
platform_notify_remove
(
dev
);
device_unbind
(
dev
);
bus_remove_device
(
dev
);
/* Tell the driver to clean up after itself.
* Note that we likely didn't allocate the device,
* so this is the driver's chance to free that up...
*/
if
(
dev
->
driver
&&
dev
->
driver
->
remove
)
dev
->
driver
->
remove
(
dev
,
REMOVE_FREE_RESOURCES
);
/* remove the driverfs directory */
device_remove_dir
(
dev
);
...
...
drivers/base/driver.c
View file @
f4ad044b
...
...
@@ -38,6 +38,7 @@ int driver_register(struct device_driver * drv)
list_add
(
&
drv
->
bus_list
,
&
drv
->
bus
->
drivers
);
write_unlock
(
&
drv
->
bus
->
lock
);
driver_make_dir
(
drv
);
driver_bind
(
drv
);
put_driver
(
drv
);
return
0
;
}
...
...
@@ -55,6 +56,7 @@ void put_driver(struct device_driver * drv)
if
(
drv
->
bus
)
{
pr_debug
(
"Unregistering driver '%s' from bus '%s'
\n
"
,
drv
->
name
,
drv
->
bus
->
name
);
driver_unbind
(
drv
);
write_lock
(
&
drv
->
bus
->
lock
);
list_del_init
(
&
drv
->
bus_list
);
write_unlock
(
&
drv
->
bus
->
lock
);
...
...
drivers/pci/hotplug.c
View file @
f4ad044b
...
...
@@ -2,8 +2,6 @@
#include <linux/module.h>
#include <linux/kmod.h>
/* for hotplug_path */
extern
int
pci_announce_device
(
struct
pci_driver
*
drv
,
struct
pci_dev
*
dev
);
#ifndef FALSE
#define FALSE (0)
#define TRUE (!FALSE)
...
...
@@ -48,28 +46,6 @@ run_sbin_hotplug(struct pci_dev *pdev, int insert)
call_usermodehelper
(
argv
[
0
],
argv
,
envp
);
}
/**
* pci_announce_device_to_drivers - tell the drivers a new device has appeared
* @dev: the device that has shown up
*
* Notifys the drivers that a new device has appeared, and also notifys
* userspace through /sbin/hotplug.
*/
void
pci_announce_device_to_drivers
(
struct
pci_dev
*
dev
)
{
struct
list_head
*
ln
;
for
(
ln
=
pci_bus_type
.
drivers
.
next
;
ln
!=
&
pci_bus_type
.
drivers
;
ln
=
ln
->
next
)
{
struct
pci_driver
*
drv
=
list_entry
(
ln
,
struct
pci_driver
,
node
);
if
(
drv
->
remove
&&
pci_announce_device
(
drv
,
dev
))
break
;
}
/* notify userspace of new hotplug device */
run_sbin_hotplug
(
dev
,
TRUE
);
}
/**
* pci_insert_device - insert a hotplug device
* @dev: the device to insert
...
...
@@ -85,7 +61,8 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
#ifdef CONFIG_PROC_FS
pci_proc_attach_device
(
dev
);
#endif
pci_announce_device_to_drivers
(
dev
);
/* notify userspace of new hotplug device */
run_sbin_hotplug
(
dev
,
TRUE
);
}
static
void
...
...
@@ -110,11 +87,7 @@ pci_free_resources(struct pci_dev *dev)
void
pci_remove_device
(
struct
pci_dev
*
dev
)
{
if
(
dev
->
driver
)
{
if
(
dev
->
driver
->
remove
)
dev
->
driver
->
remove
(
dev
);
dev
->
driver
=
NULL
;
}
put_device
(
&
dev
->
dev
);
list_del
(
&
dev
->
bus_list
);
list_del
(
&
dev
->
global_list
);
pci_free_resources
(
dev
);
...
...
@@ -128,4 +101,3 @@ pci_remove_device(struct pci_dev *dev)
EXPORT_SYMBOL
(
pci_insert_device
);
EXPORT_SYMBOL
(
pci_remove_device
);
EXPORT_SYMBOL
(
pci_announce_device_to_drivers
);
drivers/pci/pci-driver.c
View file @
f4ad044b
...
...
@@ -10,56 +10,6 @@
* Registration of PCI drivers and handling of hot-pluggable devices.
*/
/**
* pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
const
struct
pci_device_id
*
pci_match_device
(
const
struct
pci_device_id
*
ids
,
const
struct
pci_dev
*
dev
)
{
while
(
ids
->
vendor
||
ids
->
subvendor
||
ids
->
class_mask
)
{
if
((
ids
->
vendor
==
PCI_ANY_ID
||
ids
->
vendor
==
dev
->
vendor
)
&&
(
ids
->
device
==
PCI_ANY_ID
||
ids
->
device
==
dev
->
device
)
&&
(
ids
->
subvendor
==
PCI_ANY_ID
||
ids
->
subvendor
==
dev
->
subsystem_vendor
)
&&
(
ids
->
subdevice
==
PCI_ANY_ID
||
ids
->
subdevice
==
dev
->
subsystem_device
)
&&
!
((
ids
->
class
^
dev
->
class
)
&
ids
->
class_mask
))
return
ids
;
ids
++
;
}
return
NULL
;
}
int
pci_announce_device
(
struct
pci_driver
*
drv
,
struct
pci_dev
*
dev
)
{
const
struct
pci_device_id
*
id
;
int
ret
=
0
;
if
(
drv
->
id_table
)
{
id
=
pci_match_device
(
drv
->
id_table
,
dev
);
if
(
!
id
)
{
ret
=
0
;
goto
out
;
}
}
else
id
=
NULL
;
dev_probe_lock
();
if
(
drv
->
probe
(
dev
,
id
)
>=
0
)
{
dev
->
driver
=
drv
;
ret
=
1
;
}
dev_probe_unlock
();
out:
return
ret
;
}
static
int
pci_device_probe
(
struct
device
*
dev
)
{
int
error
=
0
;
...
...
@@ -68,8 +18,7 @@ static int pci_device_probe(struct device * dev)
struct
pci_dev
*
pci_dev
=
list_entry
(
dev
,
struct
pci_dev
,
dev
);
if
(
drv
->
probe
)
error
=
drv
->
probe
(
pci_dev
,
NULL
);
printk
(
"%s: returning %d
\n
"
,
__FUNCTION__
,
error
);
error
=
drv
->
probe
(
pci_dev
,
drv
->
id_table
);
return
error
>
0
?
0
:
-
ENODEV
;
}
...
...
@@ -123,7 +72,6 @@ int
pci_register_driver
(
struct
pci_driver
*
drv
)
{
int
count
=
0
;
struct
pci_dev
*
dev
;
/* initialize common driver fields */
drv
->
driver
.
name
=
drv
->
name
;
...
...
@@ -135,11 +83,6 @@ pci_register_driver(struct pci_driver *drv)
/* register with core */
count
=
driver_register
(
&
drv
->
driver
);
pci_for_each_dev
(
dev
)
{
if
(
!
pci_dev_driver
(
dev
))
pci_announce_device
(
drv
,
dev
);
}
return
count
?
count
:
1
;
}
...
...
@@ -156,20 +99,6 @@ pci_register_driver(struct pci_driver *drv)
void
pci_unregister_driver
(
struct
pci_driver
*
drv
)
{
list_t
*
node
;
node
=
drv
->
driver
.
devices
.
next
;
while
(
node
!=
&
drv
->
driver
.
devices
)
{
struct
device
*
dev
=
list_entry
(
node
,
struct
device
,
driver_list
);
struct
pci_dev
*
pci_dev
=
list_entry
(
dev
,
struct
pci_dev
,
dev
);
if
(
drv
->
remove
)
drv
->
remove
(
pci_dev
);
pci_dev
->
driver
=
NULL
;
dev
->
driver
=
NULL
;
list_del_init
(
&
dev
->
driver_list
);
}
put_driver
(
&
drv
->
driver
);
}
...
...
@@ -198,8 +127,39 @@ pci_dev_driver(const struct pci_dev *dev)
return
NULL
;
}
/**
* pci_bus_bind - Tell if a PCI device structure has a matching PCI device id structure
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
static
int
pci_bus_bind
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
{
struct
pci_dev
*
pci_dev
=
list_entry
(
dev
,
struct
pci_dev
,
dev
);
struct
pci_driver
*
pci_drv
=
list_entry
(
drv
,
struct
pci_driver
,
driver
);
const
struct
pci_device_id
*
ids
=
pci_drv
->
id_table
;
if
(
!
ids
)
return
0
;
while
(
ids
->
vendor
||
ids
->
subvendor
||
ids
->
class_mask
)
{
if
((
ids
->
vendor
==
PCI_ANY_ID
||
ids
->
vendor
==
pci_dev
->
vendor
)
&&
(
ids
->
device
==
PCI_ANY_ID
||
ids
->
device
==
pci_dev
->
device
)
&&
(
ids
->
subvendor
==
PCI_ANY_ID
||
ids
->
subvendor
==
pci_dev
->
subsystem_vendor
)
&&
(
ids
->
subdevice
==
PCI_ANY_ID
||
ids
->
subdevice
==
pci_dev
->
subsystem_device
)
&&
!
((
ids
->
class
^
pci_dev
->
class
)
&
ids
->
class_mask
))
return
1
;
ids
++
;
}
return
0
;
}
struct
bus_type
pci_bus_type
=
{
name:
"pci"
,
bind:
pci_bus_bind
,
};
static
int
__init
pci_driver_init
(
void
)
...
...
@@ -209,7 +169,6 @@ static int __init pci_driver_init(void)
subsys_initcall
(
pci_driver_init
);
EXPORT_SYMBOL
(
pci_match_device
);
EXPORT_SYMBOL
(
pci_register_driver
);
EXPORT_SYMBOL
(
pci_unregister_driver
);
EXPORT_SYMBOL
(
pci_dev_driver
);
include/linux/device.h
View file @
f4ad044b
...
...
@@ -54,7 +54,7 @@ enum {
};
struct
device
;
struct
device_driver
;
struct
bus_type
{
char
*
name
;
...
...
@@ -68,6 +68,8 @@ struct bus_type {
struct
driver_dir_entry
dir
;
struct
driver_dir_entry
device_dir
;
struct
driver_dir_entry
driver_dir
;
int
(
*
bind
)
(
struct
device
*
dev
,
struct
device_driver
*
drv
);
};
...
...
@@ -82,6 +84,11 @@ static inline struct bus_type * get_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
,
int
(
*
callback
)(
struct
device
*
dev
,
void
*
data
));
extern
int
bus_for_each_drv
(
struct
bus_type
*
bus
,
void
*
data
,
int
(
*
callback
)(
struct
device_driver
*
drv
,
void
*
data
));
struct
device_driver
{
char
*
name
;
...
...
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