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
nexedi
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