Commit 754a264c authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (158 commits)
  commit 4f705ae3
  Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
  Date:   Mon Apr 3 17:09:22 2006 -0700
  
      [PATCH] DMI: move dmi_scan.c from arch/i386 to drivers/firmware/
      
      dmi_scan.c is arch-independent and is used by i386, x86_64, and ia64.
      Currently all three arches compile it from arch/i386, which means that ia64
      and x86_64 depend on things in arch/i386 that they wouldn't otherwise care
      about.
      
      This is simply "mv arch/i386/kernel/dmi_scan.c drivers/firmware/" (removing
      trailing whitespace) and the associated Makefile changes.  All three
      architectures already set CONFIG_DMI in their top-level Kconfig files.
Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
      Cc: Andi Kleen <ak@muc.de>
      Cc: "Luck, Tony" <tony.luck@intel.com>
      Cc: Andrey Panin <pazke@orbita1.ru>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
  ...
parents f9814802 4f705ae3
......@@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
pci-dma.o i386_ksyms.o i387.o bootflag.o \
quirks.o i8237.o topology.o alternative.o
obj-y += cpu/
......
......@@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds
obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
unwind.o mca.o mca_asm.o topology.o dmi_scan.o
unwind.o mca.o mca_asm.o topology.o
obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o
......@@ -30,7 +30,6 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
dmi_scan-y += ../../i386/kernel/dmi_scan.o
# The gate DSO image is built using a special linker script.
targets += gate.so gate-syms.o
......
......@@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
x8664_ksyms.o i387.o syscall.o vsyscall.o \
setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \
dmi_scan.o pci-dma.o pci-nommu.o
pci-dma.o pci-nommu.o
obj-$(CONFIG_X86_MCE) += mce.o
obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o
......@@ -49,5 +49,3 @@ intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o
quirks-y += ../../i386/kernel/quirks.o
i8237-y += ../../i386/kernel/i8237.o
msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o
dmi_scan-y += ../../i386/kernel/dmi_scan.o
......@@ -188,6 +188,11 @@ static ssize_t driver_bind(struct device_driver *drv,
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
if (err > 0) /* success */
err = count;
else if (err == 0) /* driver didn't accept device */
err = -ENODEV;
}
put_device(dev);
put_bus(bus);
......
......@@ -562,14 +562,13 @@ int class_device_add(struct class_device *class_dev)
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
/* notify any interfaces this device is now here */
if (parent_class) {
down(&parent_class->sem);
list_add_tail(&class_dev->node, &parent_class->children);
list_for_each_entry(class_intf, &parent_class->interfaces, node)
if (class_intf->add)
class_intf->add(class_dev, class_intf);
up(&parent_class->sem);
down(&parent_class->sem);
list_add_tail(&class_dev->node, &parent_class->children);
list_for_each_entry(class_intf, &parent_class->interfaces, node) {
if (class_intf->add)
class_intf->add(class_dev, class_intf);
}
up(&parent_class->sem);
register_done:
if (error) {
......
......@@ -209,7 +209,7 @@ static void __device_release_driver(struct device * dev)
sysfs_remove_link(&dev->kobj, "driver");
klist_remove(&dev->knode_driver);
if (dev->bus->remove)
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
......
......@@ -10,6 +10,8 @@
#include <linux/vt_kern.h>
#include <linux/device.h>
#include <linux/kallsyms.h>
#include <linux/pm.h>
#include "../base.h"
#include "power.h"
......@@ -58,6 +60,7 @@ int suspend_device(struct device * dev, pm_message_t state)
if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
dev_dbg(dev, "suspending\n");
error = dev->bus->suspend(dev, state);
suspend_report_result(dev->bus->suspend, error);
}
up(&dev->sem);
return error;
......@@ -169,3 +172,12 @@ int device_power_down(pm_message_t state)
EXPORT_SYMBOL_GPL(device_power_down);
void __suspend_report_result(const char *function, void *fn, int ret)
{
if (ret) {
printk(KERN_ERR "%s(): ", function);
print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
printk("%d\n", ret);
}
}
EXPORT_SYMBOL_GPL(__suspend_report_result);
#
# Makefile for the linux kernel.
#
obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
......
......@@ -27,7 +27,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
else
printk(KERN_ERR "dmi_string: out of memory.\n");
}
}
}
return str;
}
......@@ -41,7 +41,7 @@ static int __init dmi_table(u32 base, int len, int num,
{
u8 *buf, *data;
int i = 0;
buf = dmi_ioremap(base, len);
if (buf == NULL)
return -1;
......@@ -49,9 +49,9 @@ static int __init dmi_table(u32 base, int len, int num,
data = buf;
/*
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
*/
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
*/
while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
struct dmi_header *dm = (struct dmi_header *)data;
/*
......@@ -75,7 +75,7 @@ static int __init dmi_checksum(u8 *buf)
{
u8 sum = 0;
int a;
for (a = 0; a < 15; a++)
sum += buf[a];
......
......@@ -163,6 +163,7 @@ void md_new_event(mddev_t *mddev)
{
atomic_inc(&md_event_count);
wake_up(&md_event_waiters);
sysfs_notify(&mddev->kobj, NULL, "sync_action");
}
EXPORT_SYMBOL_GPL(md_new_event);
......
......@@ -271,10 +271,12 @@ static int pci_device_suspend(struct device * dev, pm_message_t state)
struct pci_driver * drv = pci_dev->driver;
int i = 0;
if (drv && drv->suspend)
if (drv && drv->suspend) {
i = drv->suspend(pci_dev, state);
else
suspend_report_result(drv->suspend, i);
} else {
pci_save_state(pci_dev);
}
return i;
}
......
......@@ -307,9 +307,11 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
*/
if (state != PCI_D0 && dev->current_state > state)
if (state != PCI_D0 && dev->current_state > state) {
printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n",
__FUNCTION__, pci_name(dev), state, dev->current_state);
return -EINVAL;
else if (dev->current_state == state)
} else if (dev->current_state == state)
return 0; /* we're already there */
/* find PCI PM capability in list */
......
......@@ -213,11 +213,9 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
if (hcd->driver->suspend) {
retval = hcd->driver->suspend(hcd, message);
if (retval) {
dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n",
retval);
suspend_report_result(hcd->driver->suspend, retval);
if (retval)
goto done;
}
}
synchronize_irq(dev->irq);
......@@ -263,6 +261,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
* some device state (e.g. as part of clock reinit).
*/
retval = pci_set_power_state (dev, PCI_D3hot);
suspend_report_result(pci_set_power_state, retval);
if (retval == 0) {
int wake = device_can_wakeup(&hcd->self.root_hub->dev);
......
......@@ -331,7 +331,9 @@ void delete_partition(struct gendisk *disk, int part)
devfs_remove("%s/part%d", disk->devfs_name, part);
if (p->holder_dir)
kobject_unregister(p->holder_dir);
kobject_unregister(&p->kobj);
kobject_uevent(&p->kobj, KOBJ_REMOVE);
kobject_del(&p->kobj);
kobject_put(&p->kobj);
}
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
......@@ -357,7 +359,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
p->kobj.parent = &disk->kobj;
p->kobj.ktype = &ktype_part;
kobject_register(&p->kobj);
kobject_init(&p->kobj);
kobject_add(&p->kobj);
if (!disk->part_uevent_suppress)
kobject_uevent(&p->kobj, KOBJ_ADD);
partition_sysfs_add_subdir(p);
disk->part[part-1] = p;
}
......@@ -395,6 +400,8 @@ void register_disk(struct gendisk *disk)
{
struct block_device *bdev;
char *s;
int i;
struct hd_struct *p;
int err;
strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
......@@ -406,13 +413,12 @@ void register_disk(struct gendisk *disk)
return;
disk_sysfs_symlinks(disk);
disk_sysfs_add_subdirs(disk);
kobject_uevent(&disk->kobj, KOBJ_ADD);
/* No minors to use for partitions */
if (disk->minors == 1) {
if (disk->devfs_name[0] != '\0')
devfs_add_disk(disk);
return;
goto exit;
}
/* always add handle for the whole disk */
......@@ -420,16 +426,32 @@ void register_disk(struct gendisk *disk)
/* No such device (e.g., media were just removed) */
if (!get_capacity(disk))
return;
goto exit;
bdev = bdget_disk(disk, 0);
if (!bdev)
return;
goto exit;
/* scan partition table, but suppress uevents */
bdev->bd_invalidated = 1;
if (blkdev_get(bdev, FMODE_READ, 0) < 0)
return;
disk->part_uevent_suppress = 1;
err = blkdev_get(bdev, FMODE_READ, 0);
disk->part_uevent_suppress = 0;
if (err < 0)
goto exit;
blkdev_put(bdev);
exit:
/* announce disk after possible partitions are already created */
kobject_uevent(&disk->kobj, KOBJ_ADD);
/* announce possible partitions */
for (i = 1; i < disk->minors; i++) {
p = disk->part[i-1];
if (!p || !p->nr_sects)
continue;
kobject_uevent(&p->kobj, KOBJ_ADD);
}
}
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
......
......@@ -43,6 +43,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
memset(sd, 0, sizeof(*sd));
atomic_set(&sd->s_count, 1);
atomic_set(&sd->s_event, 0);
INIT_LIST_HEAD(&sd->s_children);
list_add(&sd->s_sibling, &parent_sd->s_children);
sd->s_element = element;
......
......@@ -6,6 +6,7 @@
#include <linux/fsnotify.h>
#include <linux/kobject.h>
#include <linux/namei.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
......@@ -57,6 +58,7 @@ struct sysfs_buffer {
struct sysfs_ops * ops;
struct semaphore sem;
int needs_read_fill;
int event;
};
......@@ -72,6 +74,7 @@ struct sysfs_buffer {
*/
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
struct sysfs_dirent * sd = dentry->d_fsdata;
struct attribute * attr = to_attr(dentry);
struct kobject * kobj = to_kobj(dentry->d_parent);
struct sysfs_ops * ops = buffer->ops;
......@@ -83,6 +86,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
if (!buffer->page)
return -ENOMEM;
buffer->event = atomic_read(&sd->s_event);
count = ops->show(kobj,attr,buffer->page);
buffer->needs_read_fill = 0;
BUG_ON(count > (ssize_t)PAGE_SIZE);
......@@ -348,12 +352,84 @@ static int sysfs_release(struct inode * inode, struct file * filp)
return 0;
}
/* Sysfs attribute files are pollable. The idea is that you read
* the content and then you use 'poll' or 'select' to wait for
* the content to change. When the content changes (assuming the
* manager for the kobject supports notification), poll will
* return POLLERR|POLLPRI, and select will return the fd whether
* it is waiting for read, write, or exceptions.
* Once poll/select indicates that the value has changed, you
* need to close and re-open the file, as simply seeking and reading
* again will not get new data, or reset the state of 'poll'.
* Reminder: this only works for attributes which actively support
* it, and it is not possible to test an attribute from userspace
* to see if it supports poll (Nether 'poll' or 'select' return
* an appropriate error code). When in doubt, set a suitable timeout value.
*/
static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
{
struct sysfs_buffer * buffer = filp->private_data;
struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
struct sysfs_dirent * sd = filp->f_dentry->d_fsdata;
int res = 0;
poll_wait(filp, &kobj->poll, wait);
if (buffer->event != atomic_read(&sd->s_event)) {
res = POLLERR|POLLPRI;
buffer->needs_read_fill = 1;
}
return res;
}
static struct dentry *step_down(struct dentry *dir, const char * name)
{
struct dentry * de;
if (dir == NULL || dir->d_inode == NULL)
return NULL;
mutex_lock(&dir->d_inode->i_mutex);
de = lookup_one_len(name, dir, strlen(name));
mutex_unlock(&dir->d_inode->i_mutex);
dput(dir);
if (IS_ERR(de))
return NULL;
if (de->d_inode == NULL) {
dput(de);
return NULL;
}
return de;
}
void sysfs_notify(struct kobject * k, char *dir, char *attr)
{
struct dentry *de = k->dentry;
if (de)
dget(de);
if (de && dir)
de = step_down(de, dir);
if (de && attr)
de = step_down(de, attr);
if (de) {
struct sysfs_dirent * sd = de->d_fsdata;
if (sd)
atomic_inc(&sd->s_event);
wake_up_interruptible(&k->poll);
dput(de);
}
}
EXPORT_SYMBOL_GPL(sysfs_notify);
const struct file_operations sysfs_file_operations = {
.read = sysfs_read_file,
.write = sysfs_write_file,
.llseek = generic_file_llseek,
.open = sysfs_open_file,
.release = sysfs_release,
.poll = sysfs_poll,
};
......
......@@ -11,6 +11,7 @@ extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
extern void sysfs_remove_subdir(struct dentry *);
......
......@@ -105,6 +105,7 @@ struct gendisk {
* disks that can't be partitioned. */
char disk_name[32]; /* name of major driver */
struct hd_struct **part; /* [indexed by minor] */
int part_uevent_suppress;
struct block_device_operations *fops;
struct request_queue *queue;
void *private_data;
......
......@@ -24,6 +24,7 @@
#include <linux/rwsem.h>
#include <linux/kref.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <asm/atomic.h>
#define KOBJ_NAME_LEN 20
......@@ -56,6 +57,7 @@ struct kobject {
struct kset * kset;
struct kobj_type * ktype;
struct dentry * dentry;
wait_queue_head_t poll;
};
extern int kobject_set_name(struct kobject *, const char *, ...)
......
......@@ -199,6 +199,12 @@ extern int device_suspend(pm_message_t state);
extern int dpm_runtime_suspend(struct device *, pm_message_t);
extern void dpm_runtime_resume(struct device *);
extern void __suspend_report_result(const char *function, void *fn, int ret);
#define suspend_report_result(fn, ret) \
do { \
__suspend_report_result(__FUNCTION__, fn, ret); \
} while (0)
#else /* !CONFIG_PM */
......@@ -219,6 +225,8 @@ static inline void dpm_runtime_resume(struct device * dev)
{
}
#define suspend_report_result(fn, ret) do { } while (0)
#endif
/* changes to device_may_wakeup take effect on the next pm state change.
......
......@@ -74,6 +74,7 @@ struct sysfs_dirent {
umode_t s_mode;
struct dentry * s_dentry;
struct iattr * s_iattr;
atomic_t s_event;
};
#define SYSFS_ROOT 0x0001
......@@ -117,6 +118,7 @@ int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
int sysfs_create_group(struct kobject *, const struct attribute_group *);
void sysfs_remove_group(struct kobject *, const struct attribute_group *);
void sysfs_notify(struct kobject * k, char *dir, char *attr);
#else /* CONFIG_SYSFS */
......@@ -185,6 +187,10 @@ static inline void sysfs_remove_group(struct kobject * k, const struct attribute
;
}
static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
{
}
#endif /* CONFIG_SYSFS */
#endif /* _SYSFS_H_ */
......@@ -128,6 +128,7 @@ void kobject_init(struct kobject * kobj)
{
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
init_waitqueue_head(&kobj->poll);
kobj->kset = kset_get(kobj->kset);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment