grey- and blacklisting drivers [Was: Re: Using the "best available" driver]

Kay Sievers kay.sievers at vrfy.org
Mon Dec 12 23:55:04 EST 2005


On Sun, Dec 11, 2005 at 07:43:48AM +0100, Kay Sievers wrote:
> On Fri, Dec 09, 2005 at 08:20:41PM -0800, Greg KH wrote:
> > On Thu, Dec 08, 2005 at 04:31:45PM +0100, Kay Sievers wrote:
> > > Wouldn't it make the most sense to have a generic flag to pass to _any_
> > > driver to skip the bus probing and wait for a manual bind? This would be
> > > useful for the storage controllers too, that have 1000's of disks connected,
> > > cause you don't really want to trigger all that buses at once with
> > > a modprobe.
> > 
> > Yes, that would be nice to have.
> > 
> > > That way, you would just need to disable all autobinding with the module
> > > configuration and depend on the bus device events to match a given
> > > configuration to "manually" enable every device with the udev event.
> > 
> > Crazy distro installer authors have suggested that we have a way to
> > disable all autobinding for a bus somehow, so they can do the binding
> > themselves.  They might not be so crazy after all :)
> > 
> > But as the codepaths for the "autobind" and the "manual bind" are almost
> > identical, it might be tough to disable the automatic stuff...
> 
> This quick hack works for me, but does it at the driver level, which is
> nicer to use than a global bus control.

New version, which does not do the dirty "default parameters" trick. It
depends on a regular module parameter, if "bind_mode" control at module
load or boot prompt is needed. It uses "auto" and "manual" as the values
and the sysfs file in the driver directory is called "bind_mode".

Thanks,
Kay

---
add "bind_mode" control to drivers, to specify device binding policy

This adds a sysfs control to every driver to control the automatic
binding of drivers to devices. If set to "manual", the driver will
only bind devices if explicitely asked for, by using the "bind" file.

  $ tree /sys/bus/usb/drivers/ov511/
  /sys/bus/usb/drivers/ov511/
  |-- 3-1:1.0 -> ../../../../devices/pci0000:00/0000:00:1d.1/usb3/3-1/3-1:1.0
  |-- bind
  |-- bind_mode
  |-- module -> ../../../../module/ov511
  `-- unbind

"autobind=manual" disables the automatic device binding:
  $ modprobe ov511
  $ cat /sys/bus/usb/drivers/ov511/bind_mode
  auto

  $ rmmod ov511
  $ modprobe ov511 bind_mode=manual
  $ cat /sys/bus/usb/drivers/ov511/bind_mode
  manual

Drivers need to implement a module parameter to initialize bind_mode, if
they want to offer control over bind_mode at module load or boot prompt.
---

diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index fa601b0..4feeb78 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -143,6 +143,19 @@ static int driver_helper(struct device *
 	return 0;
 }
 
+static ssize_t show_bind_mode(struct device_driver *drv, char *buf)
+{
+	return sprintf(buf, "%s\n", drv->bind_mode ? "manual" : "auto");
+}
+static ssize_t store_bind_mode(struct device_driver *drv,
+			      const char *buf, size_t count)
+{
+	if (driver_set_bind_mode(drv, buf))
+		return -EINVAL;
+	return count;
+}
+static DRIVER_ATTR(bind_mode, S_IRUSR | S_IWUSR, show_bind_mode, store_bind_mode);
+
 static ssize_t driver_unbind(struct device_driver *drv,
 			     const char *buf, size_t count)
 {
@@ -444,13 +457,15 @@ int bus_add_driver(struct device_driver 
 			return error;
 		}
 
-		driver_attach(drv);
+		if (drv->bind_mode == 0)
+			driver_attach(drv);
 		klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
 		module_add_driver(drv->owner, drv);
 
 		driver_add_attrs(bus, drv);
 		driver_create_file(drv, &driver_attr_unbind);
 		driver_create_file(drv, &driver_attr_bind);
+		driver_create_file(drv, &driver_attr_bind_mode);
 	}
 	return error;
 }
@@ -468,6 +483,7 @@ int bus_add_driver(struct device_driver 
 void bus_remove_driver(struct device_driver * drv)
 {
 	if (drv->bus) {
+		driver_remove_file(drv, &driver_attr_bind_mode);
 		driver_remove_file(drv, &driver_attr_bind);
 		driver_remove_file(drv, &driver_attr_unbind);
 		driver_remove_attrs(drv->bus, drv);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 3b419c9..048db68 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -110,6 +110,8 @@ int driver_probe_device(struct device_dr
 static int __device_attach(struct device_driver * drv, void * data)
 {
 	struct device * dev = data;
+	if (drv->bind_mode == 1)
+		return 0;
 	return driver_probe_device(drv, dev);
 }
 
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 161f3a3..c6e2fc4 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -214,11 +214,23 @@ struct device_driver *driver_find(const 
 	return NULL;
 }
 
+int driver_set_bind_mode(struct device_driver * drv, const char *mode)
+{
+	if (!strcmp(mode, "manual"))
+		drv->bind_mode = 1;
+	else if (!strcmp(mode, "auto"))
+		drv->bind_mode = 0;
+	else
+		return -ENOENT;
+	return 0;
+}
+
 EXPORT_SYMBOL_GPL(driver_register);
 EXPORT_SYMBOL_GPL(driver_unregister);
 EXPORT_SYMBOL_GPL(get_driver);
 EXPORT_SYMBOL_GPL(put_driver);
 EXPORT_SYMBOL_GPL(driver_find);
+EXPORT_SYMBOL_GPL(driver_set_bind_mode);
 
 EXPORT_SYMBOL_GPL(driver_create_file);
 EXPORT_SYMBOL_GPL(driver_remove_file);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 1b4adb1..eb03974 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -168,7 +168,9 @@ int usb_register(struct usb_driver *new_
 	new_driver->driver.probe = usb_probe_interface;
 	new_driver->driver.remove = usb_unbind_interface;
 	new_driver->driver.owner = new_driver->owner;
-
+	if (new_driver->bind_mode)
+		driver_set_bind_mode(&new_driver->driver,
+				     new_driver->bind_mode);
 	usb_lock_all_devices();
 	retval = driver_register(&new_driver->driver);
 	usb_unlock_all_devices();
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
index 036c485..3f31c2a 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -84,6 +84,10 @@
  * (See ov511.txt for detailed descriptions of these)
  **********************************************************************/
 
+static char bind_mode[8];
+module_param_string(bind_mode, bind_mode, sizeof(bind_mode), 0);
+MODULE_PARM_DESC(bind_mode, "Driver core auto/manual device binding");
+
 /* These variables (and all static globals) default to zero */
 static int autobright		= 1;
 static int autogain		= 1;
@@ -6012,7 +6016,8 @@ static struct usb_driver ov511_driver = 
 	.name =		"ov511",
 	.id_table =	device_table,
 	.probe =	ov51x_probe,
-	.disconnect =	ov51x_disconnect
+	.disconnect =	ov51x_disconnect,
+	.bind_mode =	bind_mode,
 };
 
 /****************************************************************************
diff --git a/include/linux/device.h b/include/linux/device.h
index 0cdee78..9ac1b1a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -98,6 +98,7 @@ struct device_driver {
 	struct klist_node	knode_bus;
 
 	struct module		* owner;
+	int			bind_mode;
 
 	int	(*probe)	(struct device * dev);
 	int	(*remove)	(struct device * dev);
@@ -128,6 +129,7 @@ struct driver_attribute driver_attr_##_n
 
 extern int driver_create_file(struct device_driver *, struct driver_attribute *);
 extern void driver_remove_file(struct device_driver *, struct driver_attribute *);
+extern int driver_set_bind_mode(struct device_driver * drv, const char *mode);
 
 extern int driver_for_each_device(struct device_driver * drv, struct device * start,
 				  void * data, int (*fn)(struct device *, void *));
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7a20997..61a9210 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -589,6 +589,7 @@ struct usb_driver {
 	const struct usb_device_id *id_table;
 
 	struct device_driver driver;
+	char *bind_mode;
 };
 #define	to_usb_driver(d) container_of(d, struct usb_driver, driver)
 




More information about the linux-pcmcia mailing list