Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: UIO: fix specific device driver missing statement for depmod Driver core: remove pr_fmt() from dynamic_dev_dbg() printk driver core: prevent device_for_each_child from oopsing dynamic debug: resurrect old pr_debug() semantics as pr_devel() Driver Core: early platform driver proc: mounts_poll() make consistent to mdstat_poll sysfs: sysfs poll keep the poll rule of regular file. driver core: allow non-root users to listen to uevents driver core: fix driver_match_device sysfs: don't use global workqueue in sysfs_schedule_callback()
This commit is contained in:
Коммит
74a205a3f1
|
@ -169,3 +169,62 @@ three different ways to find such a match:
|
|||
be probed later if another device registers. (Which is OK, since
|
||||
this interface is only for use with non-hotpluggable devices.)
|
||||
|
||||
|
||||
Early Platform Devices and Drivers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The early platform interfaces provide platform data to platform device
|
||||
drivers early on during the system boot. The code is built on top of the
|
||||
early_param() command line parsing and can be executed very early on.
|
||||
|
||||
Example: "earlyprintk" class early serial console in 6 steps
|
||||
|
||||
1. Registering early platform device data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code registers platform device data using the function
|
||||
early_platform_add_devices(). In the case of early serial console this
|
||||
should be hardware configuration for the serial port. Devices registered
|
||||
at this point will later on be matched against early platform drivers.
|
||||
|
||||
2. Parsing kernel command line
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code calls parse_early_param() to parse the kernel
|
||||
command line. This will execute all matching early_param() callbacks.
|
||||
User specified early platform devices will be registered at this point.
|
||||
For the early serial console case the user can specify port on the
|
||||
kernel command line as "earlyprintk=serial.0" where "earlyprintk" is
|
||||
the class string, "serial" is the name of the platfrom driver and
|
||||
0 is the platform device id. If the id is -1 then the dot and the
|
||||
id can be omitted.
|
||||
|
||||
3. Installing early platform drivers belonging to a certain class
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code may optionally force registration of all early
|
||||
platform drivers belonging to a certain class using the function
|
||||
early_platform_driver_register_all(). User specified devices from
|
||||
step 2 have priority over these. This step is omitted by the serial
|
||||
driver example since the early serial driver code should be disabled
|
||||
unless the user has specified port on the kernel command line.
|
||||
|
||||
4. Early platform driver registration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Compiled-in platform drivers making use of early_platform_init() are
|
||||
automatically registered during step 2 or 3. The serial driver example
|
||||
should use early_platform_init("earlyprintk", &platform_driver).
|
||||
|
||||
5. Probing of early platform drivers belonging to a certain class
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code calls early_platform_driver_probe() to match
|
||||
registered early platform devices associated with a certain class with
|
||||
registered early platform drivers. Matched devices will get probed().
|
||||
This step can be executed at any point during the early boot. As soon
|
||||
as possible may be good for the serial port case.
|
||||
|
||||
6. Inside the early platform driver probe()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The driver code needs to take special care during early boot, especially
|
||||
when it comes to memory allocation and interrupt registration. The code
|
||||
in the probe() function can use is_early_platform_device() to check if
|
||||
it is called at early platform device or at the regular platform device
|
||||
time. The early serial driver performs register_console() at this point.
|
||||
|
||||
For further information, see <linux/platform_device.h>.
|
||||
|
|
|
@ -115,7 +115,7 @@ extern int driver_probe_device(struct device_driver *drv, struct device *dev);
|
|||
static inline int driver_match_device(struct device_driver *drv,
|
||||
struct device *dev)
|
||||
{
|
||||
return drv->bus->match && drv->bus->match(dev, drv);
|
||||
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
|
||||
}
|
||||
|
||||
extern void sysdev_shutdown(void);
|
||||
|
|
|
@ -1142,6 +1142,9 @@ int device_for_each_child(struct device *parent, void *data,
|
|||
struct device *child;
|
||||
int error = 0;
|
||||
|
||||
if (!parent->p)
|
||||
return 0;
|
||||
|
||||
klist_iter_init(&parent->p->klist_children, &i);
|
||||
while ((child = next_device(&i)) && !error)
|
||||
error = fn(child, data);
|
||||
|
|
|
@ -990,6 +990,8 @@ int __init platform_bus_init(void)
|
|||
{
|
||||
int error;
|
||||
|
||||
early_platform_cleanup();
|
||||
|
||||
error = device_register(&platform_bus);
|
||||
if (error)
|
||||
return error;
|
||||
|
@ -1020,3 +1022,240 @@ u64 dma_get_required_mask(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dma_get_required_mask);
|
||||
#endif
|
||||
|
||||
static __initdata LIST_HEAD(early_platform_driver_list);
|
||||
static __initdata LIST_HEAD(early_platform_device_list);
|
||||
|
||||
/**
|
||||
* early_platform_driver_register
|
||||
* @edrv: early_platform driver structure
|
||||
* @buf: string passed from early_param()
|
||||
*/
|
||||
int __init early_platform_driver_register(struct early_platform_driver *epdrv,
|
||||
char *buf)
|
||||
{
|
||||
unsigned long index;
|
||||
int n;
|
||||
|
||||
/* Simply add the driver to the end of the global list.
|
||||
* Drivers will by default be put on the list in compiled-in order.
|
||||
*/
|
||||
if (!epdrv->list.next) {
|
||||
INIT_LIST_HEAD(&epdrv->list);
|
||||
list_add_tail(&epdrv->list, &early_platform_driver_list);
|
||||
}
|
||||
|
||||
/* If the user has specified device then make sure the driver
|
||||
* gets prioritized. The driver of the last device specified on
|
||||
* command line will be put first on the list.
|
||||
*/
|
||||
n = strlen(epdrv->pdrv->driver.name);
|
||||
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
|
||||
list_move(&epdrv->list, &early_platform_driver_list);
|
||||
|
||||
if (!strcmp(buf, epdrv->pdrv->driver.name))
|
||||
epdrv->requested_id = -1;
|
||||
else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10,
|
||||
&index) == 0)
|
||||
epdrv->requested_id = index;
|
||||
else
|
||||
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_add_devices - add a numbers of early platform devices
|
||||
* @devs: array of early platform devices to add
|
||||
* @num: number of early platform devices in array
|
||||
*/
|
||||
void __init early_platform_add_devices(struct platform_device **devs, int num)
|
||||
{
|
||||
struct device *dev;
|
||||
int i;
|
||||
|
||||
/* simply add the devices to list */
|
||||
for (i = 0; i < num; i++) {
|
||||
dev = &devs[i]->dev;
|
||||
|
||||
if (!dev->devres_head.next) {
|
||||
INIT_LIST_HEAD(&dev->devres_head);
|
||||
list_add_tail(&dev->devres_head,
|
||||
&early_platform_device_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_driver_register_all
|
||||
* @class_str: string to identify early platform driver class
|
||||
*/
|
||||
void __init early_platform_driver_register_all(char *class_str)
|
||||
{
|
||||
/* The "class_str" parameter may or may not be present on the kernel
|
||||
* command line. If it is present then there may be more than one
|
||||
* matching parameter.
|
||||
*
|
||||
* Since we register our early platform drivers using early_param()
|
||||
* we need to make sure that they also get registered in the case
|
||||
* when the parameter is missing from the kernel command line.
|
||||
*
|
||||
* We use parse_early_options() to make sure the early_param() gets
|
||||
* called at least once. The early_param() may be called more than
|
||||
* once since the name of the preferred device may be specified on
|
||||
* the kernel command line. early_platform_driver_register() handles
|
||||
* this case for us.
|
||||
*/
|
||||
parse_early_options(class_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_match
|
||||
* @edrv: early platform driver structure
|
||||
* @id: id to match against
|
||||
*/
|
||||
static __init struct platform_device *
|
||||
early_platform_match(struct early_platform_driver *epdrv, int id)
|
||||
{
|
||||
struct platform_device *pd;
|
||||
|
||||
list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
|
||||
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
|
||||
if (pd->id == id)
|
||||
return pd;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_left
|
||||
* @edrv: early platform driver structure
|
||||
* @id: return true if id or above exists
|
||||
*/
|
||||
static __init int early_platform_left(struct early_platform_driver *epdrv,
|
||||
int id)
|
||||
{
|
||||
struct platform_device *pd;
|
||||
|
||||
list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
|
||||
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
|
||||
if (pd->id >= id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_driver_probe_id
|
||||
* @class_str: string to identify early platform driver class
|
||||
* @id: id to match against
|
||||
* @nr_probe: number of platform devices to successfully probe before exiting
|
||||
*/
|
||||
static int __init early_platform_driver_probe_id(char *class_str,
|
||||
int id,
|
||||
int nr_probe)
|
||||
{
|
||||
struct early_platform_driver *epdrv;
|
||||
struct platform_device *match;
|
||||
int match_id;
|
||||
int n = 0;
|
||||
int left = 0;
|
||||
|
||||
list_for_each_entry(epdrv, &early_platform_driver_list, list) {
|
||||
/* only use drivers matching our class_str */
|
||||
if (strcmp(class_str, epdrv->class_str))
|
||||
continue;
|
||||
|
||||
if (id == -2) {
|
||||
match_id = epdrv->requested_id;
|
||||
left = 1;
|
||||
|
||||
} else {
|
||||
match_id = id;
|
||||
left += early_platform_left(epdrv, id);
|
||||
|
||||
/* skip requested id */
|
||||
switch (epdrv->requested_id) {
|
||||
case EARLY_PLATFORM_ID_ERROR:
|
||||
case EARLY_PLATFORM_ID_UNSET:
|
||||
break;
|
||||
default:
|
||||
if (epdrv->requested_id == id)
|
||||
match_id = EARLY_PLATFORM_ID_UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
switch (match_id) {
|
||||
case EARLY_PLATFORM_ID_ERROR:
|
||||
pr_warning("%s: unable to parse %s parameter\n",
|
||||
class_str, epdrv->pdrv->driver.name);
|
||||
/* fall-through */
|
||||
case EARLY_PLATFORM_ID_UNSET:
|
||||
match = NULL;
|
||||
break;
|
||||
default:
|
||||
match = early_platform_match(epdrv, match_id);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if (epdrv->pdrv->probe(match))
|
||||
pr_warning("%s: unable to probe %s early.\n",
|
||||
class_str, match->name);
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n >= nr_probe)
|
||||
break;
|
||||
}
|
||||
|
||||
if (left)
|
||||
return n;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_driver_probe
|
||||
* @class_str: string to identify early platform driver class
|
||||
* @nr_probe: number of platform devices to successfully probe before exiting
|
||||
* @user_only: only probe user specified early platform devices
|
||||
*/
|
||||
int __init early_platform_driver_probe(char *class_str,
|
||||
int nr_probe,
|
||||
int user_only)
|
||||
{
|
||||
int k, n, i;
|
||||
|
||||
n = 0;
|
||||
for (i = -2; n < nr_probe; i++) {
|
||||
k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
|
||||
|
||||
if (k < 0)
|
||||
break;
|
||||
|
||||
n += k;
|
||||
|
||||
if (user_only)
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* early_platform_cleanup - clean up early platform code
|
||||
*/
|
||||
void __init early_platform_cleanup(void)
|
||||
{
|
||||
struct platform_device *pd, *pd2;
|
||||
|
||||
/* clean up the devres list used to chain devices */
|
||||
list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
|
||||
dev.devres_head) {
|
||||
list_del(&pd->dev.devres_head);
|
||||
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -147,5 +147,6 @@ static void __exit hilscher_exit_module(void)
|
|||
module_init(hilscher_init_module);
|
||||
module_exit(hilscher_exit_module);
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, hilscher_pci_ids);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
|
||||
|
|
|
@ -648,14 +648,14 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
|
|||
{
|
||||
struct proc_mounts *p = file->private_data;
|
||||
struct mnt_namespace *ns = p->ns;
|
||||
unsigned res = 0;
|
||||
unsigned res = POLLIN | POLLRDNORM;
|
||||
|
||||
poll_wait(file, &ns->poll, wait);
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (p->event != ns->event) {
|
||||
p->event = ns->event;
|
||||
res = POLLERR;
|
||||
res |= POLLERR | POLLPRI;
|
||||
}
|
||||
spin_unlock(&vfsmount_lock);
|
||||
|
||||
|
|
|
@ -446,11 +446,11 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
|
|||
if (buffer->event != atomic_read(&od->event))
|
||||
goto trigger;
|
||||
|
||||
return 0;
|
||||
return DEFAULT_POLLMASK;
|
||||
|
||||
trigger:
|
||||
buffer->needs_read_fill = 1;
|
||||
return POLLERR|POLLPRI;
|
||||
return DEFAULT_POLLMASK|POLLERR|POLLPRI;
|
||||
}
|
||||
|
||||
void sysfs_notify_dirent(struct sysfs_dirent *sd)
|
||||
|
@ -667,6 +667,7 @@ struct sysfs_schedule_callback_struct {
|
|||
struct work_struct work;
|
||||
};
|
||||
|
||||
static struct workqueue_struct *sysfs_workqueue;
|
||||
static DEFINE_MUTEX(sysfs_workq_mutex);
|
||||
static LIST_HEAD(sysfs_workq);
|
||||
static void sysfs_schedule_callback_work(struct work_struct *work)
|
||||
|
@ -715,11 +716,20 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
|
|||
mutex_lock(&sysfs_workq_mutex);
|
||||
list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list)
|
||||
if (ss->kobj == kobj) {
|
||||
module_put(owner);
|
||||
mutex_unlock(&sysfs_workq_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
mutex_unlock(&sysfs_workq_mutex);
|
||||
|
||||
if (sysfs_workqueue == NULL) {
|
||||
sysfs_workqueue = create_workqueue("sysfsd");
|
||||
if (sysfs_workqueue == NULL) {
|
||||
module_put(owner);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ss = kmalloc(sizeof(*ss), GFP_KERNEL);
|
||||
if (!ss) {
|
||||
module_put(owner);
|
||||
|
@ -735,7 +745,7 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
|
|||
mutex_lock(&sysfs_workq_mutex);
|
||||
list_add_tail(&ss->workq_list, &sysfs_workq);
|
||||
mutex_unlock(&sysfs_workq_mutex);
|
||||
schedule_work(&ss->work);
|
||||
queue_work(sysfs_workqueue, &ss->work);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
|
||||
|
|
|
@ -70,7 +70,7 @@ extern int ddebug_remove_module(char *mod_name);
|
|||
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
|
||||
if (__dynamic_dbg_enabled(descriptor)) \
|
||||
dev_printk(KERN_DEBUG, dev, \
|
||||
KBUILD_MODNAME ": " pr_fmt(fmt),\
|
||||
KBUILD_MODNAME ": " fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -247,6 +247,7 @@ struct obs_kernel_param {
|
|||
|
||||
/* Relies on boot_command_line being set */
|
||||
void __init parse_early_param(void);
|
||||
void __init parse_early_options(char *cmdline);
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/**
|
||||
|
|
|
@ -377,6 +377,15 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
|
|||
#define pr_cont(fmt, ...) \
|
||||
printk(KERN_CONT fmt, ##__VA_ARGS__)
|
||||
|
||||
/* pr_devel() should produce zero code unless DEBUG is defined */
|
||||
#ifdef DEBUG
|
||||
#define pr_devel(fmt, ...) \
|
||||
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
|
||||
#else
|
||||
#define pr_devel(fmt, ...) \
|
||||
({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
|
||||
#endif
|
||||
|
||||
/* If you are writing a driver, please use dev_dbg instead */
|
||||
#if defined(DEBUG)
|
||||
#define pr_debug(fmt, ...) \
|
||||
|
|
|
@ -77,4 +77,46 @@ extern int platform_driver_probe(struct platform_driver *driver,
|
|||
#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
|
||||
#define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data))
|
||||
|
||||
/* early platform driver interface */
|
||||
struct early_platform_driver {
|
||||
const char *class_str;
|
||||
struct platform_driver *pdrv;
|
||||
struct list_head list;
|
||||
int requested_id;
|
||||
};
|
||||
|
||||
#define EARLY_PLATFORM_ID_UNSET -2
|
||||
#define EARLY_PLATFORM_ID_ERROR -3
|
||||
|
||||
extern int early_platform_driver_register(struct early_platform_driver *epdrv,
|
||||
char *buf);
|
||||
extern void early_platform_add_devices(struct platform_device **devs, int num);
|
||||
|
||||
static inline int is_early_platform_device(struct platform_device *pdev)
|
||||
{
|
||||
return !pdev->dev.driver;
|
||||
}
|
||||
|
||||
extern void early_platform_driver_register_all(char *class_str);
|
||||
extern int early_platform_driver_probe(char *class_str,
|
||||
int nr_probe, int user_only);
|
||||
extern void early_platform_cleanup(void);
|
||||
|
||||
|
||||
#ifndef MODULE
|
||||
#define early_platform_init(class_string, platform_driver) \
|
||||
static __initdata struct early_platform_driver early_driver = { \
|
||||
.class_str = class_string, \
|
||||
.pdrv = platform_driver, \
|
||||
.requested_id = EARLY_PLATFORM_ID_UNSET, \
|
||||
}; \
|
||||
static int __init early_platform_driver_setup_func(char *buf) \
|
||||
{ \
|
||||
return early_platform_driver_register(&early_driver, buf); \
|
||||
} \
|
||||
early_param(class_string, early_platform_driver_setup_func)
|
||||
#else /* MODULE */
|
||||
#define early_platform_init(class_string, platform_driver)
|
||||
#endif /* MODULE */
|
||||
|
||||
#endif /* _PLATFORM_DEVICE_H_ */
|
||||
|
|
|
@ -492,6 +492,11 @@ static int __init do_early_param(char *param, char *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __init parse_early_options(char *cmdline)
|
||||
{
|
||||
parse_args("early options", cmdline, NULL, 0, do_early_param);
|
||||
}
|
||||
|
||||
/* Arch code calls this early on, or if not, just before other parsing. */
|
||||
void __init parse_early_param(void)
|
||||
{
|
||||
|
@ -503,7 +508,7 @@ void __init parse_early_param(void)
|
|||
|
||||
/* All fall through to do_early_param. */
|
||||
strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
|
||||
parse_args("early options", tmp_cmdline, NULL, 0, do_early_param);
|
||||
parse_early_options(tmp_cmdline);
|
||||
done = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -328,7 +328,7 @@ static int __init kobject_uevent_init(void)
|
|||
"kobject_uevent: unable to create netlink socket!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче