Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6
This commit is contained in:
commit
f65e77693a
|
@ -90,7 +90,7 @@ void device_remove_file(struct device *, struct device_attribute *);
|
|||
|
||||
It also defines this helper for defining device attributes:
|
||||
|
||||
#define DEVICE_ATTR(_name,_mode,_show,_store) \
|
||||
#define DEVICE_ATTR(_name, _mode, _show, _store) \
|
||||
struct device_attribute dev_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name) , .mode = _mode }, \
|
||||
.show = _show, \
|
||||
|
@ -99,14 +99,14 @@ struct device_attribute dev_attr_##_name = { \
|
|||
|
||||
For example, declaring
|
||||
|
||||
static DEVICE_ATTR(foo,0644,show_foo,store_foo);
|
||||
static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
|
||||
|
||||
is equivalent to doing:
|
||||
|
||||
static struct device_attribute dev_attr_foo = {
|
||||
.attr = {
|
||||
.name = "foo",
|
||||
.mode = 0644,
|
||||
.mode = S_IWUSR | S_IRUGO,
|
||||
},
|
||||
.show = show_foo,
|
||||
.store = store_foo,
|
||||
|
@ -121,8 +121,8 @@ set of sysfs operations for forwarding read and write calls to the
|
|||
show and store methods of the attribute owners.
|
||||
|
||||
struct sysfs_ops {
|
||||
ssize_t (*show)(struct kobject *, struct attribute *,char *);
|
||||
ssize_t (*store)(struct kobject *,struct attribute *,const char *);
|
||||
ssize_t (*show)(struct kobject *, struct attribute *, char *);
|
||||
ssize_t (*store)(struct kobject *, struct attribute *, const char *);
|
||||
};
|
||||
|
||||
[ Subsystems should have already defined a struct kobj_type as a
|
||||
|
@ -137,7 +137,7 @@ calls the associated methods.
|
|||
|
||||
To illustrate:
|
||||
|
||||
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
|
||||
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
|
||||
#define to_dev(d) container_of(d, struct device, kobj)
|
||||
|
||||
static ssize_t
|
||||
|
@ -148,7 +148,7 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
|
|||
ssize_t ret = 0;
|
||||
|
||||
if (dev_attr->show)
|
||||
ret = dev_attr->show(dev,buf);
|
||||
ret = dev_attr->show(dev, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -216,16 +216,16 @@ A very simple (and naive) implementation of a device attribute is:
|
|||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf,"%s\n",dev->name);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", dev->name);
|
||||
}
|
||||
|
||||
static ssize_t store_name(struct device * dev, const char * buf)
|
||||
{
|
||||
sscanf(buf,"%20s",dev->name);
|
||||
return strlen(buf);
|
||||
sscanf(buf, "%20s", dev->name);
|
||||
return strnlen(buf, PAGE_SIZE);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name,S_IRUGO,show_name,store_name);
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
|
||||
|
||||
|
||||
(Note that the real implementation doesn't allow userspace to set the
|
||||
|
@ -290,7 +290,7 @@ struct device_attribute {
|
|||
|
||||
Declaring:
|
||||
|
||||
DEVICE_ATTR(_name,_str,_mode,_show,_store);
|
||||
DEVICE_ATTR(_name, _str, _mode, _show, _store);
|
||||
|
||||
Creation/Removal:
|
||||
|
||||
|
@ -310,7 +310,7 @@ struct bus_attribute {
|
|||
|
||||
Declaring:
|
||||
|
||||
BUS_ATTR(_name,_mode,_show,_store)
|
||||
BUS_ATTR(_name, _mode, _show, _store)
|
||||
|
||||
Creation/Removal:
|
||||
|
||||
|
@ -331,7 +331,7 @@ struct driver_attribute {
|
|||
|
||||
Declaring:
|
||||
|
||||
DRIVER_ATTR(_name,_mode,_show,_store)
|
||||
DRIVER_ATTR(_name, _mode, _show, _store)
|
||||
|
||||
Creation/Removal:
|
||||
|
||||
|
|
|
@ -156,7 +156,9 @@ static ssize_t driver_unbind(struct device_driver *drv,
|
|||
device_release_driver(dev);
|
||||
err = count;
|
||||
}
|
||||
return err;
|
||||
if (err)
|
||||
return err;
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
|
||||
|
||||
|
@ -358,7 +360,7 @@ int bus_add_device(struct device * dev)
|
|||
if (bus) {
|
||||
pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
|
||||
device_attach(dev);
|
||||
klist_add_tail(&bus->klist_devices, &dev->knode_bus);
|
||||
klist_add_tail(&dev->knode_bus, &bus->klist_devices);
|
||||
error = device_add_attrs(bus, dev);
|
||||
if (!error) {
|
||||
sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
|
||||
|
@ -446,7 +448,7 @@ int bus_add_driver(struct device_driver * drv)
|
|||
}
|
||||
|
||||
driver_attach(drv);
|
||||
klist_add_tail(&bus->klist_drivers, &drv->knode_bus);
|
||||
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
|
||||
module_add_driver(drv->owner, drv);
|
||||
|
||||
driver_add_attrs(bus, drv);
|
||||
|
|
|
@ -299,10 +299,8 @@ static void class_dev_release(struct kobject * kobj)
|
|||
|
||||
pr_debug("device class '%s': release.\n", cd->class_id);
|
||||
|
||||
if (cd->devt_attr) {
|
||||
kfree(cd->devt_attr);
|
||||
cd->devt_attr = NULL;
|
||||
}
|
||||
kfree(cd->devt_attr);
|
||||
cd->devt_attr = NULL;
|
||||
|
||||
if (cls->release)
|
||||
cls->release(cd);
|
||||
|
@ -452,10 +450,29 @@ void class_device_initialize(struct class_device *class_dev)
|
|||
INIT_LIST_HEAD(&class_dev->node);
|
||||
}
|
||||
|
||||
static char *make_class_name(struct class_device *class_dev)
|
||||
{
|
||||
char *name;
|
||||
int size;
|
||||
|
||||
size = strlen(class_dev->class->name) +
|
||||
strlen(kobject_name(&class_dev->kobj)) + 2;
|
||||
|
||||
name = kmalloc(size, GFP_KERNEL);
|
||||
if (!name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
strcpy(name, class_dev->class->name);
|
||||
strcat(name, ":");
|
||||
strcat(name, kobject_name(&class_dev->kobj));
|
||||
return name;
|
||||
}
|
||||
|
||||
int class_device_add(struct class_device *class_dev)
|
||||
{
|
||||
struct class * parent = NULL;
|
||||
struct class_interface * class_intf;
|
||||
char *class_name = NULL;
|
||||
int error;
|
||||
|
||||
class_dev = class_device_get(class_dev);
|
||||
|
@ -500,9 +517,13 @@ int class_device_add(struct class_device *class_dev)
|
|||
}
|
||||
|
||||
class_device_add_attrs(class_dev);
|
||||
if (class_dev->dev)
|
||||
if (class_dev->dev) {
|
||||
class_name = make_class_name(class_dev);
|
||||
sysfs_create_link(&class_dev->kobj,
|
||||
&class_dev->dev->kobj, "device");
|
||||
sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
|
||||
class_name);
|
||||
}
|
||||
|
||||
/* notify any interfaces this device is now here */
|
||||
if (parent) {
|
||||
|
@ -519,6 +540,7 @@ int class_device_add(struct class_device *class_dev)
|
|||
if (error && parent)
|
||||
class_put(parent);
|
||||
class_device_put(class_dev);
|
||||
kfree(class_name);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -584,6 +606,7 @@ void class_device_del(struct class_device *class_dev)
|
|||
{
|
||||
struct class * parent = class_dev->class;
|
||||
struct class_interface * class_intf;
|
||||
char *class_name = NULL;
|
||||
|
||||
if (parent) {
|
||||
down(&parent->sem);
|
||||
|
@ -594,8 +617,11 @@ void class_device_del(struct class_device *class_dev)
|
|||
up(&parent->sem);
|
||||
}
|
||||
|
||||
if (class_dev->dev)
|
||||
if (class_dev->dev) {
|
||||
class_name = make_class_name(class_dev);
|
||||
sysfs_remove_link(&class_dev->kobj, "device");
|
||||
sysfs_remove_link(&class_dev->dev->kobj, class_name);
|
||||
}
|
||||
if (class_dev->devt_attr)
|
||||
class_device_remove_file(class_dev, class_dev->devt_attr);
|
||||
class_device_remove_attrs(class_dev);
|
||||
|
@ -605,6 +631,7 @@ void class_device_del(struct class_device *class_dev)
|
|||
|
||||
if (parent)
|
||||
class_put(parent);
|
||||
kfree(class_name);
|
||||
}
|
||||
|
||||
void class_device_unregister(struct class_device *class_dev)
|
||||
|
|
|
@ -249,7 +249,7 @@ int device_add(struct device *dev)
|
|||
if ((error = bus_add_device(dev)))
|
||||
goto BusError;
|
||||
if (parent)
|
||||
klist_add_tail(&parent->klist_children, &dev->knode_parent);
|
||||
klist_add_tail(&dev->knode_parent, &parent->klist_children);
|
||||
|
||||
/* notify platform of device entry */
|
||||
if (platform_notify)
|
||||
|
|
|
@ -42,7 +42,7 @@ void device_bind_driver(struct device * dev)
|
|||
{
|
||||
pr_debug("bound device '%s' to driver '%s'\n",
|
||||
dev->bus_id, dev->driver->name);
|
||||
klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver);
|
||||
klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
|
||||
sysfs_create_link(&dev->driver->kobj, &dev->kobj,
|
||||
kobject_name(&dev->kobj));
|
||||
sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
|
||||
|
|
|
@ -288,6 +288,27 @@ void sysdev_shutdown(void)
|
|||
up(&sysdev_drivers_lock);
|
||||
}
|
||||
|
||||
static void __sysdev_resume(struct sys_device *dev)
|
||||
{
|
||||
struct sysdev_class *cls = dev->cls;
|
||||
struct sysdev_driver *drv;
|
||||
|
||||
/* First, call the class-specific one */
|
||||
if (cls->resume)
|
||||
cls->resume(dev);
|
||||
|
||||
/* Call auxillary drivers next. */
|
||||
list_for_each_entry(drv, &cls->drivers, entry) {
|
||||
if (drv->resume)
|
||||
drv->resume(dev);
|
||||
}
|
||||
|
||||
/* Call global drivers. */
|
||||
list_for_each_entry(drv, &sysdev_drivers, entry) {
|
||||
if (drv->resume)
|
||||
drv->resume(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysdev_suspend - Suspend all system devices.
|
||||
|
@ -305,38 +326,93 @@ void sysdev_shutdown(void)
|
|||
int sysdev_suspend(pm_message_t state)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
struct sys_device *sysdev, *err_dev;
|
||||
struct sysdev_driver *drv, *err_drv;
|
||||
int ret;
|
||||
|
||||
pr_debug("Suspending System Devices\n");
|
||||
|
||||
list_for_each_entry_reverse(cls, &system_subsys.kset.list,
|
||||
kset.kobj.entry) {
|
||||
struct sys_device * sysdev;
|
||||
|
||||
pr_debug("Suspending type '%s':\n",
|
||||
kobject_name(&cls->kset.kobj));
|
||||
|
||||
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
|
||||
struct sysdev_driver * drv;
|
||||
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
|
||||
|
||||
/* Call global drivers first. */
|
||||
list_for_each_entry(drv, &sysdev_drivers, entry) {
|
||||
if (drv->suspend)
|
||||
drv->suspend(sysdev, state);
|
||||
if (drv->suspend) {
|
||||
ret = drv->suspend(sysdev, state);
|
||||
if (ret)
|
||||
goto gbl_driver;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call auxillary drivers next. */
|
||||
list_for_each_entry(drv, &cls->drivers, entry) {
|
||||
if (drv->suspend)
|
||||
drv->suspend(sysdev, state);
|
||||
if (drv->suspend) {
|
||||
ret = drv->suspend(sysdev, state);
|
||||
if (ret)
|
||||
goto aux_driver;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now call the generic one */
|
||||
if (cls->suspend)
|
||||
cls->suspend(sysdev, state);
|
||||
if (cls->suspend) {
|
||||
ret = cls->suspend(sysdev, state);
|
||||
if (ret)
|
||||
goto cls_driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
/* resume current sysdev */
|
||||
cls_driver:
|
||||
drv = NULL;
|
||||
printk(KERN_ERR "Class suspend failed for %s\n",
|
||||
kobject_name(&sysdev->kobj));
|
||||
|
||||
aux_driver:
|
||||
if (drv)
|
||||
printk(KERN_ERR "Class driver suspend failed for %s\n",
|
||||
kobject_name(&sysdev->kobj));
|
||||
list_for_each_entry(err_drv, &cls->drivers, entry) {
|
||||
if (err_drv == drv)
|
||||
break;
|
||||
if (err_drv->resume)
|
||||
err_drv->resume(sysdev);
|
||||
}
|
||||
drv = NULL;
|
||||
|
||||
gbl_driver:
|
||||
if (drv)
|
||||
printk(KERN_ERR "sysdev driver suspend failed for %s\n",
|
||||
kobject_name(&sysdev->kobj));
|
||||
list_for_each_entry(err_drv, &sysdev_drivers, entry) {
|
||||
if (err_drv == drv)
|
||||
break;
|
||||
if (err_drv->resume)
|
||||
err_drv->resume(sysdev);
|
||||
}
|
||||
/* resume other sysdevs in current class */
|
||||
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
|
||||
if (err_dev == sysdev)
|
||||
break;
|
||||
pr_debug(" %s\n", kobject_name(&err_dev->kobj));
|
||||
__sysdev_resume(err_dev);
|
||||
}
|
||||
|
||||
/* resume other classes */
|
||||
list_for_each_entry_continue(cls, &system_subsys.kset.list,
|
||||
kset.kobj.entry) {
|
||||
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
|
||||
pr_debug(" %s\n", kobject_name(&err_dev->kobj));
|
||||
__sysdev_resume(err_dev);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -362,25 +438,9 @@ int sysdev_resume(void)
|
|||
kobject_name(&cls->kset.kobj));
|
||||
|
||||
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
|
||||
struct sysdev_driver * drv;
|
||||
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
|
||||
|
||||
/* First, call the class-specific one */
|
||||
if (cls->resume)
|
||||
cls->resume(sysdev);
|
||||
|
||||
/* Call auxillary drivers next. */
|
||||
list_for_each_entry(drv, &cls->drivers, entry) {
|
||||
if (drv->resume)
|
||||
drv->resume(sysdev);
|
||||
}
|
||||
|
||||
/* Call global drivers. */
|
||||
list_for_each_entry(drv, &sysdev_drivers, entry) {
|
||||
if (drv->resume)
|
||||
drv->resume(sysdev);
|
||||
}
|
||||
|
||||
__sysdev_resume(sysdev);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -493,6 +493,8 @@ static struct floppy_struct user_params[N_DRIVE];
|
|||
|
||||
static sector_t floppy_sizes[256];
|
||||
|
||||
static char floppy_device_name[] = "floppy";
|
||||
|
||||
/*
|
||||
* The driver is trying to determine the correct media format
|
||||
* while probing is set. rw_interrupt() clears it after a
|
||||
|
@ -4191,18 +4193,24 @@ static int __init floppy_setup(char *str)
|
|||
|
||||
static int have_no_fdc = -ENODEV;
|
||||
|
||||
static ssize_t floppy_cmos_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *p;
|
||||
int drive;
|
||||
|
||||
p = container_of(dev, struct platform_device,dev);
|
||||
drive = p->id;
|
||||
return sprintf(buf, "%X\n", UDP->cmos);
|
||||
}
|
||||
DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL);
|
||||
|
||||
static void floppy_device_release(struct device *dev)
|
||||
{
|
||||
complete(&device_release);
|
||||
}
|
||||
|
||||
static struct platform_device floppy_device = {
|
||||
.name = "floppy",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.release = floppy_device_release,
|
||||
}
|
||||
};
|
||||
static struct platform_device floppy_device[N_DRIVE];
|
||||
|
||||
static struct kobject *floppy_find(dev_t dev, int *part, void *data)
|
||||
{
|
||||
|
@ -4370,20 +4378,26 @@ static int __init floppy_init(void)
|
|||
goto out_flush_work;
|
||||
}
|
||||
|
||||
err = platform_device_register(&floppy_device);
|
||||
if (err)
|
||||
goto out_flush_work;
|
||||
|
||||
for (drive = 0; drive < N_DRIVE; drive++) {
|
||||
if (!(allowed_drive_mask & (1 << drive)))
|
||||
continue;
|
||||
if (fdc_state[FDC(drive)].version == FDC_NONE)
|
||||
continue;
|
||||
|
||||
floppy_device[drive].name = floppy_device_name;
|
||||
floppy_device[drive].id = drive;
|
||||
floppy_device[drive].dev.release = floppy_device_release;
|
||||
|
||||
err = platform_device_register(&floppy_device[drive]);
|
||||
if (err)
|
||||
goto out_flush_work;
|
||||
|
||||
device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
|
||||
/* to be cleaned up... */
|
||||
disks[drive]->private_data = (void *)(long)drive;
|
||||
disks[drive]->queue = floppy_queue;
|
||||
disks[drive]->flags |= GENHD_FL_REMOVABLE;
|
||||
disks[drive]->driverfs_dev = &floppy_device.dev;
|
||||
disks[drive]->driverfs_dev = &floppy_device[drive].dev;
|
||||
add_disk(disks[drive]);
|
||||
}
|
||||
|
||||
|
@ -4603,10 +4617,11 @@ void cleanup_module(void)
|
|||
fdc_state[FDC(drive)].version != FDC_NONE) {
|
||||
del_gendisk(disks[drive]);
|
||||
unregister_devfs_entries(drive);
|
||||
device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
|
||||
platform_device_unregister(&floppy_device[drive]);
|
||||
}
|
||||
put_disk(disks[drive]);
|
||||
}
|
||||
platform_device_unregister(&floppy_device);
|
||||
devfs_remove("floppy");
|
||||
|
||||
del_timer_sync(&fd_timeout);
|
||||
|
|
|
@ -782,7 +782,7 @@ static int usb_register_bus(struct usb_bus *bus)
|
|||
return -E2BIG;
|
||||
}
|
||||
|
||||
bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum);
|
||||
bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb_host%d", busnum);
|
||||
if (IS_ERR(bus->class_dev)) {
|
||||
clear_bit(busnum, busmap.busmap);
|
||||
up(&usb_bus_list_lock);
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
* This file is rleased under the GPL v2.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_KLIST_H
|
||||
#define _LINUX_KLIST_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/kref.h>
|
||||
|
@ -31,8 +34,8 @@ struct klist_node {
|
|||
struct completion n_removed;
|
||||
};
|
||||
|
||||
extern void klist_add_tail(struct klist * k, struct klist_node * n);
|
||||
extern void klist_add_head(struct klist * k, struct klist_node * n);
|
||||
extern void klist_add_tail(struct klist_node * n, struct klist * k);
|
||||
extern void klist_add_head(struct klist_node * n, struct klist * k);
|
||||
|
||||
extern void klist_del(struct klist_node * n);
|
||||
extern void klist_remove(struct klist_node * n);
|
||||
|
@ -53,3 +56,4 @@ extern void klist_iter_init_node(struct klist * k, struct klist_iter * i,
|
|||
extern void klist_iter_exit(struct klist_iter * i);
|
||||
extern struct klist_node * klist_next(struct klist_iter * i);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -79,11 +79,11 @@ static void klist_node_init(struct klist * k, struct klist_node * n)
|
|||
|
||||
/**
|
||||
* klist_add_head - Initialize a klist_node and add it to front.
|
||||
* @k: klist it's going on.
|
||||
* @n: node we're adding.
|
||||
* @k: klist it's going on.
|
||||
*/
|
||||
|
||||
void klist_add_head(struct klist * k, struct klist_node * n)
|
||||
void klist_add_head(struct klist_node * n, struct klist * k)
|
||||
{
|
||||
klist_node_init(k, n);
|
||||
add_head(k, n);
|
||||
|
@ -94,11 +94,11 @@ EXPORT_SYMBOL_GPL(klist_add_head);
|
|||
|
||||
/**
|
||||
* klist_add_tail - Initialize a klist_node and add it to back.
|
||||
* @k: klist it's going on.
|
||||
* @n: node we're adding.
|
||||
* @k: klist it's going on.
|
||||
*/
|
||||
|
||||
void klist_add_tail(struct klist * k, struct klist_node * n)
|
||||
void klist_add_tail(struct klist_node * n, struct klist * k)
|
||||
{
|
||||
klist_node_init(k, n);
|
||||
add_tail(k, n);
|
||||
|
|
Loading…
Reference in New Issue