Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2aca47d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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: (28 commits)
  sysfs: Shadow directory support
  Driver Core: Increase the default timeout value of the firmware subsystem
  Driver core: allow to delay the uevent at device creation time
  Driver core: add device_type to struct device
  Driver core: add uevent vars for devices of a class
  SYSFS: Fix missing include of list.h in sysfs.h
  HOWTO: Add a reference to Harbison and Steele
  sysfs: error handling in sysfs, fill_read_buffer()
  kobject: kobject_put cleanup
  sysfs: kobject_put cleanup
  sysfs: suppress lockdep warnings
  Driver core: fix race in sysfs between sysfs_remove_file() and read()/write()
  driver core: Change function call order in device_bind_driver().
  driver core: Don't stop probing on ->probe errors.
  driver core fixes: device_register() retval check in platform.c
  driver core fixes: make_class_name() retval checks
  /sys/modules/*/holders
  USB: add the sysfs driver name to all modules
  SERIO: add the sysfs driver name to all modules
  PCI: add the sysfs driver name to all modules
  ...
parents 7677ced4 b592fcfe
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ are not a good substitute for a solid C education and/or years of
experience, the following books are good for, if anything, reference:
experience, the following books are good for, if anything, reference:
 - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
 - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
 - "Practical C Programming" by Steve Oualline [O'Reilly]
 - "Practical C Programming" by Steve Oualline [O'Reilly]
 - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]


The kernel is written using GNU C and the GNU toolchain.  While it
The kernel is written using GNU C and the GNU toolchain.  While it
adheres to the ISO C89 standard, it uses a number of extensions that are
adheres to the ISO C89 standard, it uses a number of extensions that are
+14 −7
Original line number Original line Diff line number Diff line
@@ -364,7 +364,7 @@ char *make_class_name(const char *name, struct kobject *kobj)


	class_name = kmalloc(size, GFP_KERNEL);
	class_name = kmalloc(size, GFP_KERNEL);
	if (!class_name)
	if (!class_name)
		return ERR_PTR(-ENOMEM);
		return NULL;


	strcpy(class_name, name);
	strcpy(class_name, name);
	strcat(class_name, ":");
	strcat(class_name, ":");
@@ -411,8 +411,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev)
		return 0;
		return 0;


	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
	error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
	if (class_name)
				  class_name);
		error = sysfs_create_link(&class_dev->dev->kobj,
					  &class_dev->kobj, class_name);
	else
		error = -ENOMEM;
	kfree(class_name);
	kfree(class_name);
	return error;
	return error;
}
}
@@ -425,6 +428,7 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev)
		return;
		return;


	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
	if (class_name)
		sysfs_remove_link(&class_dev->dev->kobj, class_name);
		sysfs_remove_link(&class_dev->dev->kobj, class_name);
	kfree(class_name);
	kfree(class_name);
}
}
@@ -863,9 +867,12 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
	if (class_dev->dev) {
	if (class_dev->dev) {
		new_class_name = make_class_name(class_dev->class->name,
		new_class_name = make_class_name(class_dev->class->name,
						 &class_dev->kobj);
						 &class_dev->kobj);
		sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
		if (new_class_name)
				  new_class_name);
			sysfs_create_link(&class_dev->dev->kobj,
		sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
					  &class_dev->kobj, new_class_name);
		if (old_class_name)
			sysfs_remove_link(&class_dev->dev->kobj,
						old_class_name);
	}
	}
#endif
#endif
	class_device_put(class_dev);
	class_device_put(class_dev);
+133 −70
Original line number Original line Diff line number Diff line
@@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj)


	if (dev->release)
	if (dev->release)
		dev->release(dev);
		dev->release(dev);
	else if (dev->type && dev->type->release)
		dev->type->release(dev);
	else if (dev->class && dev->class->dev_release)
	else if (dev->class && dev->class->dev_release)
		dev->class->dev_release(dev);
		dev->class->dev_release(dev);
	else {
	else {
@@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
			       "MINOR=%u", MINOR(dev->devt));
			       "MINOR=%u", MINOR(dev->devt));
	}
	}


	if (dev->driver)
		add_uevent_var(envp, num_envp, &i,
			       buffer, buffer_size, &length,
			       "DRIVER=%s", dev->driver->name);

#ifdef CONFIG_SYSFS_DEPRECATED
#ifdef CONFIG_SYSFS_DEPRECATED
	/* add bus name (same as SUBSYSTEM, deprecated) */
	if (dev->class) {
	if (dev->bus)
		struct device *parent = dev->parent;

		/* find first bus device in parent chain */
		while (parent && !parent->bus)
			parent = parent->parent;
		if (parent && parent->bus) {
			const char *path;

			path = kobject_get_path(&parent->kobj, GFP_KERNEL);
			add_uevent_var(envp, num_envp, &i,
			add_uevent_var(envp, num_envp, &i,
				       buffer, buffer_size, &length,
				       buffer, buffer_size, &length,
			       "PHYSDEVBUS=%s", dev->bus->name);
				       "PHYSDEVPATH=%s", path);
#endif
			kfree(path);


	/* add driver name (PHYSDEV* values are deprecated)*/
	if (dev->driver) {
			add_uevent_var(envp, num_envp, &i,
			add_uevent_var(envp, num_envp, &i,
				       buffer, buffer_size, &length,
				       buffer, buffer_size, &length,
			       "DRIVER=%s", dev->driver->name);
				       "PHYSDEVBUS=%s", parent->bus->name);
#ifdef CONFIG_SYSFS_DEPRECATED

			if (parent->driver)
				add_uevent_var(envp, num_envp, &i,
					       buffer, buffer_size, &length,
					       "PHYSDEVDRIVER=%s", parent->driver->name);
		}
	} else if (dev->bus) {
		add_uevent_var(envp, num_envp, &i,
			       buffer, buffer_size, &length,
			       "PHYSDEVBUS=%s", dev->bus->name);

		if (dev->driver)
			add_uevent_var(envp, num_envp, &i,
			add_uevent_var(envp, num_envp, &i,
				       buffer, buffer_size, &length,
				       buffer, buffer_size, &length,
				       "PHYSDEVDRIVER=%s", dev->driver->name);
				       "PHYSDEVDRIVER=%s", dev->driver->name);
#endif
	}
	}
#endif


	/* terminate, set to next free slot, shrink available space */
	/* terminate, set to next free slot, shrink available space */
	envp[i] = NULL;
	envp[i] = NULL;
@@ -184,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
	if (dev->bus && dev->bus->uevent) {
	if (dev->bus && dev->bus->uevent) {
		/* have the bus specific function add its stuff */
		/* have the bus specific function add its stuff */
		retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
		retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
			if (retval) {
		if (retval)
			pr_debug ("%s - uevent() returned %d\n",
			pr_debug ("%s: bus uevent() returned %d\n",
				  __FUNCTION__, retval);
				  __FUNCTION__, retval);
	}
	}
	}


	if (dev->class && dev->class->dev_uevent) {
	if (dev->class && dev->class->dev_uevent) {
		/* have the class specific function add its stuff */
		/* have the class specific function add its stuff */
		retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
		retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
			if (retval) {
		if (retval)
				pr_debug("%s - dev_uevent() returned %d\n",
			pr_debug("%s: class uevent() returned %d\n",
				 __FUNCTION__, retval);
				 __FUNCTION__, retval);
	}
	}

	if (dev->type && dev->type->uevent) {
		/* have the device type specific fuction add its stuff */
		retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
		if (retval)
			pr_debug("%s: dev_type uevent() returned %d\n",
				 __FUNCTION__, retval);
	}
	}


	return retval;
	return retval;
@@ -247,37 +277,50 @@ static void device_remove_groups(struct device *dev)
static int device_add_attrs(struct device *dev)
static int device_add_attrs(struct device *dev)
{
{
	struct class *class = dev->class;
	struct class *class = dev->class;
	struct device_type *type = dev->type;
	int error = 0;
	int error = 0;
	int i;
	int i;


	if (!class)
	if (class && class->dev_attrs) {
		return 0;

	if (class->dev_attrs) {
		for (i = 0; attr_name(class->dev_attrs[i]); i++) {
		for (i = 0; attr_name(class->dev_attrs[i]); i++) {
			error = device_create_file(dev, &class->dev_attrs[i]);
			error = device_create_file(dev, &class->dev_attrs[i]);
			if (error)
			if (error)
				break;
				break;
		}
		}
	}
		if (error)
		if (error)
			while (--i >= 0)
			while (--i >= 0)
				device_remove_file(dev, &class->dev_attrs[i]);
				device_remove_file(dev, &class->dev_attrs[i]);
	}

	if (type && type->attrs) {
		for (i = 0; attr_name(type->attrs[i]); i++) {
			error = device_create_file(dev, &type->attrs[i]);
			if (error)
				break;
		}
		if (error)
			while (--i >= 0)
				device_remove_file(dev, &type->attrs[i]);
	}

	return error;
	return error;
}
}


static void device_remove_attrs(struct device *dev)
static void device_remove_attrs(struct device *dev)
{
{
	struct class *class = dev->class;
	struct class *class = dev->class;
	struct device_type *type = dev->type;
	int i;
	int i;


	if (!class)
	if (class && class->dev_attrs) {
		return;

	if (class->dev_attrs) {
		for (i = 0; attr_name(class->dev_attrs[i]); i++)
		for (i = 0; attr_name(class->dev_attrs[i]); i++)
			device_remove_file(dev, &class->dev_attrs[i]);
			device_remove_file(dev, &class->dev_attrs[i]);
	}
	}

	if (type && type->attrs) {
		for (i = 0; attr_name(type->attrs[i]); i++)
			device_remove_file(dev, &type->attrs[i]);
	}
}
}




@@ -390,22 +433,23 @@ void device_initialize(struct device *dev)
}
}


#ifdef CONFIG_SYSFS_DEPRECATED
#ifdef CONFIG_SYSFS_DEPRECATED
static int setup_parent(struct device *dev, struct device *parent)
static struct kobject * get_device_parent(struct device *dev,
					  struct device *parent)
{
{
	/* Set the parent to the class, not the parent device */
	/* Set the parent to the class, not the parent device */
	/* this keeps sysfs from having a symlink to make old udevs happy */
	/* this keeps sysfs from having a symlink to make old udevs happy */
	if (dev->class)
	if (dev->class)
		dev->kobj.parent = &dev->class->subsys.kset.kobj;
		return &dev->class->subsys.kset.kobj;
	else if (parent)
	else if (parent)
		dev->kobj.parent = &parent->kobj;
		return &parent->kobj;


	return 0;
	return NULL;
}
}
#else
#else
static int virtual_device_parent(struct device *dev)
static struct kobject * virtual_device_parent(struct device *dev)
{
{
	if (!dev->class)
	if (!dev->class)
		return -ENODEV;
		return ERR_PTR(-ENODEV);


	if (!dev->class->virtual_dir) {
	if (!dev->class->virtual_dir) {
		static struct kobject *virtual_dir = NULL;
		static struct kobject *virtual_dir = NULL;
@@ -415,25 +459,31 @@ static int virtual_device_parent(struct device *dev)
		dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
		dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
	}
	}


	dev->kobj.parent = dev->class->virtual_dir;
	return dev->class->virtual_dir;
	return 0;
}
}


static int setup_parent(struct device *dev, struct device *parent)
static struct kobject * get_device_parent(struct device *dev,
					  struct device *parent)
{
{
	int error;

	/* if this is a class device, and has no parent, create one */
	/* if this is a class device, and has no parent, create one */
	if ((dev->class) && (parent == NULL)) {
	if ((dev->class) && (parent == NULL)) {
		error = virtual_device_parent(dev);
		return virtual_device_parent(dev);
		if (error)
			return error;
	} else if (parent)
	} else if (parent)
		dev->kobj.parent = &parent->kobj;
		return &parent->kobj;
	return NULL;
}


#endif
static int setup_parent(struct device *dev, struct device *parent)
{
	struct kobject *kobj;
	kobj = get_device_parent(dev, parent);
	if (IS_ERR(kobj))
		return PTR_ERR(kobj);
	if (kobj)
		dev->kobj.parent = kobj;
	return 0;
	return 0;
}
}
#endif


/**
/**
 *	device_add - add device to device hierarchy.
 *	device_add - add device to device hierarchy.
@@ -520,9 +570,13 @@ int device_add(struct device *dev)
					  &dev->kobj, dev->bus_id);
					  &dev->kobj, dev->bus_id);
#ifdef CONFIG_SYSFS_DEPRECATED
#ifdef CONFIG_SYSFS_DEPRECATED
		if (parent) {
		if (parent) {
			sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
			sysfs_create_link(&dev->kobj, &dev->parent->kobj,
			class_name = make_class_name(dev->class->name, &dev->kobj);
							"device");
			sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
			class_name = make_class_name(dev->class->name,
							&dev->kobj);
			if (class_name)
				sysfs_create_link(&dev->parent->kobj,
						  &dev->kobj, class_name);
		}
		}
#endif
#endif
	}
	}
@@ -535,6 +589,7 @@ int device_add(struct device *dev)
		goto PMError;
		goto PMError;
	if ((error = bus_add_device(dev)))
	if ((error = bus_add_device(dev)))
		goto BusError;
		goto BusError;
	if (!dev->uevent_suppress)
		kobject_uevent(&dev->kobj, KOBJ_ADD);
		kobject_uevent(&dev->kobj, KOBJ_ADD);
	if ((error = bus_attach_device(dev)))
	if ((error = bus_attach_device(dev)))
		goto AttachError;
		goto AttachError;
@@ -665,7 +720,9 @@ void device_del(struct device * dev)
		if (parent) {
		if (parent) {
			char *class_name = make_class_name(dev->class->name,
			char *class_name = make_class_name(dev->class->name,
							   &dev->kobj);
							   &dev->kobj);
			sysfs_remove_link(&dev->parent->kobj, class_name);
			if (class_name)
				sysfs_remove_link(&dev->parent->kobj,
						  class_name);
			kfree(class_name);
			kfree(class_name);
			sysfs_remove_link(&dev->kobj, "device");
			sysfs_remove_link(&dev->kobj, "device");
		}
		}
@@ -968,20 +1025,25 @@ static int device_move_class_links(struct device *dev,


	class_name = make_class_name(dev->class->name, &dev->kobj);
	class_name = make_class_name(dev->class->name, &dev->kobj);
	if (!class_name) {
	if (!class_name) {
		error = PTR_ERR(class_name);
		error = -ENOMEM;
		class_name = NULL;
		goto out;
		goto out;
	}
	}
	if (old_parent) {
	if (old_parent) {
		sysfs_remove_link(&dev->kobj, "device");
		sysfs_remove_link(&dev->kobj, "device");
		sysfs_remove_link(&old_parent->kobj, class_name);
		sysfs_remove_link(&old_parent->kobj, class_name);
	}
	}
	error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
	if (new_parent) {
		error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
					  "device");
		if (error)
		if (error)
			goto out;
			goto out;
	error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
		error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
					  class_name);
		if (error)
		if (error)
			sysfs_remove_link(&dev->kobj, "device");
			sysfs_remove_link(&dev->kobj, "device");
	}
	else
		error = 0;
out:
out:
	kfree(class_name);
	kfree(class_name);
	return error;
	return error;
@@ -993,29 +1055,28 @@ out:
/**
/**
 * device_move - moves a device to a new parent
 * device_move - moves a device to a new parent
 * @dev: the pointer to the struct device to be moved
 * @dev: the pointer to the struct device to be moved
 * @new_parent: the new parent of the device
 * @new_parent: the new parent of the device (can by NULL)
 */
 */
int device_move(struct device *dev, struct device *new_parent)
int device_move(struct device *dev, struct device *new_parent)
{
{
	int error;
	int error;
	struct device *old_parent;
	struct device *old_parent;
	struct kobject *new_parent_kobj;


	dev = get_device(dev);
	dev = get_device(dev);
	if (!dev)
	if (!dev)
		return -EINVAL;
		return -EINVAL;


	if (!device_is_registered(dev)) {
		error = -EINVAL;
		goto out;
	}
	new_parent = get_device(new_parent);
	new_parent = get_device(new_parent);
	if (!new_parent) {
	new_parent_kobj = get_device_parent (dev, new_parent);
		error = -EINVAL;
	if (IS_ERR(new_parent_kobj)) {
		error = PTR_ERR(new_parent_kobj);
		put_device(new_parent);
		goto out;
		goto out;
	}
	}
	pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
	pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
		new_parent->bus_id);
		 new_parent ? new_parent->bus_id : "<NULL>");
	error = kobject_move(&dev->kobj, &new_parent->kobj);
	error = kobject_move(&dev->kobj, new_parent_kobj);
	if (error) {
	if (error) {
		put_device(new_parent);
		put_device(new_parent);
		goto out;
		goto out;
@@ -1024,6 +1085,7 @@ int device_move(struct device *dev, struct device *new_parent)
	dev->parent = new_parent;
	dev->parent = new_parent;
	if (old_parent)
	if (old_parent)
		klist_remove(&dev->knode_parent);
		klist_remove(&dev->knode_parent);
	if (new_parent)
		klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
		klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
	if (!dev->class)
	if (!dev->class)
		goto out_put;
		goto out_put;
@@ -1032,6 +1094,7 @@ int device_move(struct device *dev, struct device *new_parent)
		/* We ignore errors on cleanup since we're hosed anyway... */
		/* We ignore errors on cleanup since we're hosed anyway... */
		device_move_class_links(dev, new_parent, old_parent);
		device_move_class_links(dev, new_parent, old_parent);
		if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
		if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
			if (new_parent)
				klist_remove(&dev->knode_parent);
				klist_remove(&dev->knode_parent);
			if (old_parent)
			if (old_parent)
				klist_add_tail(&dev->knode_parent,
				klist_add_tail(&dev->knode_parent,
+12 −9
Original line number Original line Diff line number Diff line
@@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev)
 */
 */
int device_bind_driver(struct device *dev)
int device_bind_driver(struct device *dev)
{
{
	int ret;

	ret = driver_sysfs_add(dev);
	if (!ret)
		driver_bound(dev);
		driver_bound(dev);
	return driver_sysfs_add(dev);
	return ret;
}
}


struct stupid_thread_structure {
struct stupid_thread_structure {
@@ -136,18 +140,17 @@ probe_failed:
	driver_sysfs_remove(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;
	dev->driver = NULL;


	if (ret == -ENODEV || ret == -ENXIO) {
	if (ret != -ENODEV && ret != -ENXIO) {
		/* Driver matched, but didn't support device
		 * or device not found.
		 * Not an error; keep going.
		 */
		ret = 0;
	} else {
		/* driver matched but the probe failed */
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev->bus_id, ret);
		       drv->name, dev->bus_id, ret);
	}
	}
	/*
	 * Ignore errors returned by ->probe so that the next driver can try
	 * its luck.
	 */
	ret = 0;
done:
done:
	kfree(data);
	kfree(data);
	atomic_dec(&probe_count);
	atomic_dec(&probe_count);
+1 −1
Original line number Original line Diff line number Diff line
@@ -35,7 +35,7 @@ enum {
	FW_STATUS_READY_NOHOTPLUG,
	FW_STATUS_READY_NOHOTPLUG,
};
};


static int loading_timeout = 10;	/* In seconds */
static int loading_timeout = 60;	/* In seconds */


/* fw_lock could be moved to 'struct firmware_priv' but since it is just
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
 * guarding for corner cases a global lock should be OK */
 * guarding for corner cases a global lock should be OK */
Loading