linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Driver core change request
@ 2004-10-07  4:54 Dmitry Torokhov
  2004-10-07 21:40 ` Greg KH
  0 siblings, 1 reply; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-07  4:54 UTC (permalink / raw)
  To: LKML; +Cc: Greg KH, Patrick Mochel

Hi,

I am reworking my sysfs serio patches (trying to get dynamic psmouse
protocol switching) and I am wondering if we could export device_attach
function. Serio system allows user to request device rescan - force current
driver to let go off the device and find another suitable driver. Also user
can manually request device to be disconnected/connected to a driver. By
having device_attach exported I could get rid of some duplicated code.

Also serio allows user to request a specific driver to be bound to a device
in case there are several options (psmouse/serio_raw for example). To do
that and not poke in the driver core guts too much I need something like the
following:

int driver_probe_device(struct device_driver *dev, struct device *dev)
{
        int error;
        
	dev->driver = drv;
        if (drv->probe) {
        	if ((error = drv->probe(dev))) {
                	dev->driver = NULL;
                        return error;
                }
	}
        device_bind_driver(dev);
        return 0;
}


static int bus_match(struct device * dev, struct device_driver * drv)
{
        if (dev->bus->match(dev, drv))
		return driver_probe_device(drv, dev);

        return -ENODEV;
}

I.e driver_probe_device is exported. Does it have a chance to be accepted?

Thanks!

-- 
Dmitry

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Driver core change request
  2004-10-07  4:54 Driver core change request Dmitry Torokhov
@ 2004-10-07 21:40 ` Greg KH
  2004-10-08  2:59   ` Dmitry Torokhov
  0 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2004-10-07 21:40 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Patrick Mochel

On Wed, Oct 06, 2004 at 11:54:18PM -0500, Dmitry Torokhov wrote:
> Hi,
> 
> I am reworking my sysfs serio patches (trying to get dynamic psmouse
> protocol switching) and I am wondering if we could export device_attach
> function. Serio system allows user to request device rescan - force current
> driver to let go off the device and find another suitable driver. Also user
> can manually request device to be disconnected/connected to a driver. By
> having device_attach exported I could get rid of some duplicated code.

driver_attach() is global, so I don't have a problem with making
device_attach() global either.  Just send me a patch :)

> Also serio allows user to request a specific driver to be bound to a device
> in case there are several options (psmouse/serio_raw for example). To do
> that and not poke in the driver core guts too much I need something like the
> following:
> 
> int driver_probe_device(struct device_driver *dev, struct device *dev)
> {
>         int error;
>         
> 	dev->driver = drv;
>         if (drv->probe) {
>         	if ((error = drv->probe(dev))) {
>                 	dev->driver = NULL;
>                         return error;
>                 }
> 	}
>         device_bind_driver(dev);
>         return 0;
> }
> 
> 
> static int bus_match(struct device * dev, struct device_driver * drv)
> {
>         if (dev->bus->match(dev, drv))
> 		return driver_probe_device(drv, dev);
> 
>         return -ENODEV;
> }
> 
> I.e driver_probe_device is exported. Does it have a chance to be accepted?

What's wrong with doing what the pci core does in this situation and
call driver_attach()?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Driver core change request
  2004-10-07 21:40 ` Greg KH
@ 2004-10-08  2:59   ` Dmitry Torokhov
  2004-10-08 21:48     ` Greg KH
  0 siblings, 1 reply; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-08  2:59 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

On Thursday 07 October 2004 04:40 pm, Greg KH wrote:
> On Wed, Oct 06, 2004 at 11:54:18PM -0500, Dmitry Torokhov wrote:
> > Hi,
> > 
> > I am reworking my sysfs serio patches (trying to get dynamic psmouse
> > protocol switching) and I am wondering if we could export device_attach
> > function. Serio system allows user to request device rescan - force current
> > driver to let go off the device and find another suitable driver. Also user
> > can manually request device to be disconnected/connected to a driver. By
> > having device_attach exported I could get rid of some duplicated code.
> 
> driver_attach() is global, so I don't have a problem with making
> device_attach() global either.  Just send me a patch :)
> 

OK. BTW, while driver_attach is global it is not exported. Should I mark both
of them EXPORT_GPL_ONLY? 

> > 
> > I.e driver_probe_device is exported. Does it have a chance to be accepted?
> 
> What's wrong with doing what the pci core does in this situation and
> call driver_attach()?
> 

Well, I need to be able to work with a specific port so when I am doing

	echo -n "serio_raw" > /sys/bus/serio/devices/serio1/driver

I want only serio1 be affected, not every disconnected port that can work
with serio_raw. driver_attach() will claim all of them. 

The difference is that serio system allows you to have several drivers
that can drive the same hardware and user gets to chose which driver gets
the honors. I.e given 4 PS/2 ports in the system user might want to have
raw access to port #2 (via serio_raw) while using standard psmouse driver
for the rest of them. With PCI if you have 2 drivers and 2 exactly same
cards you do not have ability to bind first driver to one of the cards and
second driver to the other.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Driver core change request
  2004-10-08  2:59   ` Dmitry Torokhov
@ 2004-10-08 21:48     ` Greg KH
  2004-10-12  6:29       ` Dmitry Torokhov
  0 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2004-10-08 21:48 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Patrick Mochel

On Thu, Oct 07, 2004 at 09:59:10PM -0500, Dmitry Torokhov wrote:
> On Thursday 07 October 2004 04:40 pm, Greg KH wrote:
> > On Wed, Oct 06, 2004 at 11:54:18PM -0500, Dmitry Torokhov wrote:
> > > Hi,
> > > 
> > > I am reworking my sysfs serio patches (trying to get dynamic psmouse
> > > protocol switching) and I am wondering if we could export device_attach
> > > function. Serio system allows user to request device rescan - force current
> > > driver to let go off the device and find another suitable driver. Also user
> > > can manually request device to be disconnected/connected to a driver. By
> > > having device_attach exported I could get rid of some duplicated code.
> > 
> > driver_attach() is global, so I don't have a problem with making
> > device_attach() global either.  Just send me a patch :)
> > 
> 
> OK. BTW, while driver_attach is global it is not exported. Should I mark both
> of them EXPORT_GPL_ONLY? 

No, pci can not be a module.  Can your serio core be a module?  If not,
just make it global.  But if so, yes, EXPORT_SYMBOL_GPL() is the proper
marking.

> > > I.e driver_probe_device is exported. Does it have a chance to be accepted?
> > 
> > What's wrong with doing what the pci core does in this situation and
> > call driver_attach()?
> > 
> 
> Well, I need to be able to work with a specific port so when I am doing
> 
> 	echo -n "serio_raw" > /sys/bus/serio/devices/serio1/driver
> 
> I want only serio1 be affected, not every disconnected port that can work
> with serio_raw. driver_attach() will claim all of them. 
> 
> The difference is that serio system allows you to have several drivers
> that can drive the same hardware and user gets to chose which driver gets
> the honors. I.e given 4 PS/2 ports in the system user might want to have
> raw access to port #2 (via serio_raw) while using standard psmouse driver
> for the rest of them. With PCI if you have 2 drivers and 2 exactly same
> cards you do not have ability to bind first driver to one of the cards and
> second driver to the other.

Nice.  We want to make this kind of functionality avaiable to all
busses, and not have it be a bus only type feature.  So if you can see
any way it could be moved into the core, I'd be all for it.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Driver core change request
  2004-10-08 21:48     ` Greg KH
@ 2004-10-12  6:29       ` Dmitry Torokhov
  2004-10-12  6:31         ` [PATCH 1/4] Driver core: export device_attach Dmitry Torokhov
  2004-10-21  7:05         ` Driver core change request Dmitry Torokhov
  0 siblings, 2 replies; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-12  6:29 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

On Friday 08 October 2004 04:48 pm, Greg KH wrote:
> On Thu, Oct 07, 2004 at 09:59:10PM -0500, Dmitry Torokhov wrote:
> > On Thursday 07 October 2004 04:40 pm, Greg KH wrote:
> > > On Wed, Oct 06, 2004 at 11:54:18PM -0500, Dmitry Torokhov wrote:
> > > > Hi,
> > > > 
> > > > I am reworking my sysfs serio patches (trying to get dynamic psmouse
> > > > protocol switching) and I am wondering if we could export device_attach
> > > > function. Serio system allows user to request device rescan - force current
> > > > driver to let go off the device and find another suitable driver. Also user
> > > > can manually request device to be disconnected/connected to a driver. By
> > > > having device_attach exported I could get rid of some duplicated code.
> > > 
> > > driver_attach() is global, so I don't have a problem with making
> > > device_attach() global either.  Just send me a patch :)
> > > 
> > 
> > OK. BTW, while driver_attach is global it is not exported. Should I mark both
> > of them EXPORT_GPL_ONLY? 
> 
> No, pci can not be a module.  Can your serio core be a module?  If not,
> just make it global.  But if so, yes, EXPORT_SYMBOL_GPL() is the proper
> marking.
> 

Yes serio and gameport (which I am planning to convert to driver model as well)
can be built as modules.

> > > > I.e driver_probe_device is exported. Does it have a chance to be accepted?
> > > 
> > > What's wrong with doing what the pci core does in this situation and
> > > call driver_attach()?
> > > 
> > 
> > Well, I need to be able to work with a specific port so when I am doing
> > 
> > 	echo -n "serio_raw" > /sys/bus/serio/devices/serio1/driver
> > 
> > I want only serio1 be affected, not every disconnected port that can work
> > with serio_raw. driver_attach() will claim all of them. 
> > 
> > The difference is that serio system allows you to have several drivers
> > that can drive the same hardware and user gets to chose which driver gets
> > the honors. I.e given 4 PS/2 ports in the system user might want to have
> > raw access to port #2 (via serio_raw) while using standard psmouse driver
> > for the rest of them. With PCI if you have 2 drivers and 2 exactly same
> > cards you do not have ability to bind first driver to one of the cards and
> > second driver to the other.
> 
> Nice.  We want to make this kind of functionality avaiable to all
> busses, and not have it be a bus only type feature.  So if you can see
> any way it could be moved into the core, I'd be all for it.
> 

I have been looking at it entire weekend and I do not presently see a way to
make this facility truly generic. That is because pretty much all buses
perform additional steps besides code in driver->remove() which driver core
does is not aware of. What is needed it bus->device_disconnect function that
would disconnect device and probably destroy all children.

For now I added:

- "driver" default device attribute that produces name of currently bound
  driver uppon read.
- bus->rebind_handler method that is called when someone writes to "driver"
  attribute and allows to perform bunctions like disconnecting device or
  rebinding it to alternative driver in bus-specific way.
- "bind_mode" default device and driver attributes that can be "auto" or
  "manual". When device or driver marked as manual bind device_attach()
  and driver_attach() will ignore them. They are expected to be bound by
  bus->rebind_handler (via driver_probe_device()).

I also renamed bus_match to driver_probe_device() and exported it, along
with device_attach and driver_attach.

Please let me know if its acceptable.

The patches are suitable for importing with bkimport utility (by Bjorn
Helgaas?) that allows preserve per-file comments.

	http://www.geocities.com/dt_or/misc/

-- 
Dmitry

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/4] Driver core: export device_attach
  2004-10-12  6:29       ` Dmitry Torokhov
@ 2004-10-12  6:31         ` Dmitry Torokhov
  2004-10-12  6:31           ` [PATCH 2/4] Driver core: add driver_probe_device Dmitry Torokhov
  2004-10-29 16:37           ` [PATCH 1/4] Driver core: export device_attach Greg KH
  2004-10-21  7:05         ` Driver core change request Dmitry Torokhov
  1 sibling, 2 replies; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-12  6:31 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

#### AUTHOR dtor_core@ameritech.net
#### COMMENT START
### Comments for ChangeSet
Driver core: make device_attach() global and export it and
             driver_attach() so subsystems can have finer
             control over binding process.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
### Comments for drivers/base/bus.c
Make device_attach() global and export it and driver_attach()
### Comments for include/linux/device.h
Make device_attach() global.
#### COMMENT END

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/11 00:19:18-05:00 dtor_core@ameritech.net 
#   Driver core: make device_attach() global and export it and
#                driver_attach() so subsystems can have finer
#                control over binding process.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/device.h
#   2004/10/10 23:56:49-05:00 dtor_core@ameritech.net +1 -0
#   Make device_attach() global.
# 
# drivers/base/bus.c
#   2004/10/10 23:56:49-05:00 dtor_core@ameritech.net +3 -1
#   Make device_attach() global and export it and driver_attach()
# 
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	2004-10-12 01:27:27 -05:00
+++ b/drivers/base/bus.c	2004-10-12 01:27:27 -05:00
@@ -288,7 +288,7 @@
  *	Walk the list of drivers that the bus has and call bus_match()
  *	for each pair. If a compatible pair is found, break out and return.
  */
-static int device_attach(struct device * dev)
+int device_attach(struct device * dev)
 {
  	struct bus_type * bus = dev->bus;
 	struct list_head * entry;
@@ -728,6 +728,8 @@
 
 EXPORT_SYMBOL_GPL(device_bind_driver);
 EXPORT_SYMBOL_GPL(device_release_driver);
+EXPORT_SYMBOL_GPL(device_attach);
+EXPORT_SYMBOL_GPL(driver_attach);
 
 EXPORT_SYMBOL_GPL(bus_add_device);
 EXPORT_SYMBOL_GPL(bus_remove_device);
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	2004-10-12 01:27:27 -05:00
+++ b/include/linux/device.h	2004-10-12 01:27:27 -05:00
@@ -327,6 +327,7 @@
  */
 extern void device_bind_driver(struct device * dev);
 extern void device_release_driver(struct device * dev);
+extern int  device_attach(struct device * dev);
 extern void driver_attach(struct device_driver * drv);
 
 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/4] Driver core: add driver_probe_device
  2004-10-12  6:31         ` [PATCH 1/4] Driver core: export device_attach Dmitry Torokhov
@ 2004-10-12  6:31           ` Dmitry Torokhov
  2004-10-12  6:32             ` [PATCH 3/4] Driver core: add "driver" default attribute Dmitry Torokhov
  2004-10-29 16:37             ` [PATCH 2/4] Driver core: add driver_probe_device Greg KH
  2004-10-29 16:37           ` [PATCH 1/4] Driver core: export device_attach Greg KH
  1 sibling, 2 replies; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-12  6:31 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

#### AUTHOR dtor_core@ameritech.net
#### COMMENT START
### Comments for ChangeSet
Driver core: rename bus_match into driver_probe_device and export
             it so subsystems can bind an individual device to a
             specific driver without getting involved with driver
             core internals.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
### Comments for drivers/base/bus.c
Rename bus_match() to driver_probe_device() and export it. 
### Comments for include/linux/device.h
Add driver_probe_device()
#### COMMENT END

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/11 00:19:57-05:00 dtor_core@ameritech.net 
#   Driver core: rename bus_match into driver_probe_device and export
#                it so subsystems can bind an individual device to a
#                specific driver without getting involved with driver
#                core internals.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/device.h
#   2004/10/10 23:57:30-05:00 dtor_core@ameritech.net +2 -1
#   Add driver_probe_device()
# 
# drivers/base/bus.c
#   2004/10/10 23:57:30-05:00 dtor_core@ameritech.net +29 -26
#   Rename bus_match() to driver_probe_device() and export it. 
# 
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	2004-10-12 01:28:06 -05:00
+++ b/drivers/base/bus.c	2004-10-12 01:28:06 -05:00
@@ -250,34 +250,35 @@
 
 
 /**
- *	bus_match - check compatibility between device & driver.
- *	@dev:	device.
+ *	driver_probe_device - attempt to bind device & driver.
  *	@drv:	driver.
+ *	@dev:	device.
  *
- *	First, we call the bus's match function, which should compare
- *	the device IDs the driver supports with the device IDs of the
- *	device. Note we don't do this ourselves because we don't know
- *	the format of the ID structures, nor what is to be considered
- *	a match and what is not.
+ *	First, we call the bus's match function, if one present, which
+ *	should compare the device IDs the driver supports with the
+ *	device IDs of the device. Note we don't do this ourselves
+ *	because we don't know the format of the ID structures, nor what
+ *	is to be considered a match and what is not.
  *
  *	If we find a match, we call @drv->probe(@dev) if it exists, and
- *	call attach() above.
+ *	call device_bind_driver() above.
  */
-static int bus_match(struct device * dev, struct device_driver * drv)
+int driver_probe_device(struct device_driver * drv, struct device * dev)
 {
-	int error = -ENODEV;
-	if (dev->bus->match(dev, drv)) {
-		dev->driver = drv;
-		if (drv->probe) {
-			if ((error = drv->probe(dev))) {
-				dev->driver = NULL;
-				return error;
-			}
+	if (drv->bus->match && !drv->bus->match(dev, drv))
+		return -ENODEV;
+
+	dev->driver = drv;
+	if (drv->probe) {
+		int error = drv->probe(dev);
+		if (error) {
+			dev->driver = NULL;
+			return error;
 		}
-		device_bind_driver(dev);
-		error = 0;
 	}
-	return error;
+
+	device_bind_driver(dev);
+	return 0;
 }
 
 
@@ -285,8 +286,9 @@
  *	device_attach - try to attach device to a driver.
  *	@dev:	device.
  *
- *	Walk the list of drivers that the bus has and call bus_match()
- *	for each pair. If a compatible pair is found, break out and return.
+ *	Walk the list of drivers that the bus has and call
+ *	driver_probe_device() for each pair. If a compatible
+ *	pair is found, break out and return.
  */
 int device_attach(struct device * dev)
 {
@@ -302,7 +304,7 @@
 	if (bus->match) {
 		list_for_each(entry, &bus->drivers.list) {
 			struct device_driver * drv = to_drv(entry);
-			error = bus_match(dev, drv);
+			error = driver_probe_device(drv, dev);
 			if (!error)
 				/* success, driver matched */
 				return 1;
@@ -327,8 +329,8 @@
  *	If bus_match() returns 0 and the @dev->driver is set, we've found
  *	a compatible pair.
  *
- *	Note that we ignore the -ENODEV error from bus_match(), since it's
- *	perfectly valid for a driver not to bind to any devices.
+ *	Note that we ignore the -ENODEV error from driver_probe_device(),
+ *	since it's perfectly valid for a driver not to bind to any devices.
  */
 void driver_attach(struct device_driver * drv)
 {
@@ -342,7 +344,7 @@
 	list_for_each(entry, &bus->devices.list) {
 		struct device * dev = container_of(entry, struct device, bus_list);
 		if (!dev->driver) {
-			error = bus_match(dev, drv);
+			error = driver_probe_device(drv, dev);
 			if (error && (error != -ENODEV))
 				/* driver matched but the probe failed */
 				printk(KERN_WARNING
@@ -726,6 +728,7 @@
 EXPORT_SYMBOL_GPL(bus_for_each_dev);
 EXPORT_SYMBOL_GPL(bus_for_each_drv);
 
+EXPORT_SYMBOL_GPL(driver_probe_device);
 EXPORT_SYMBOL_GPL(device_bind_driver);
 EXPORT_SYMBOL_GPL(device_release_driver);
 EXPORT_SYMBOL_GPL(device_attach);
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	2004-10-12 01:28:06 -05:00
+++ b/include/linux/device.h	2004-10-12 01:28:06 -05:00
@@ -322,9 +322,10 @@
 		     int (*fn)(struct device *, void *));
 
 /*
- * Manual binding of a device to driver. See drivers/base/bus.c 
+ * Manual binding of a device to driver. See drivers/base/bus.c
  * for information on use.
  */
+extern int  driver_probe_device(struct device_driver * drv, struct device * dev);
 extern void device_bind_driver(struct device * dev);
 extern void device_release_driver(struct device * dev);
 extern int  device_attach(struct device * dev);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/4] Driver core: add "driver" default attribute
  2004-10-12  6:31           ` [PATCH 2/4] Driver core: add driver_probe_device Dmitry Torokhov
@ 2004-10-12  6:32             ` Dmitry Torokhov
  2004-10-12  6:33               ` [PATCH 4/4] Driver core: add "bind_mode" " Dmitry Torokhov
  2004-10-29 16:37             ` [PATCH 2/4] Driver core: add driver_probe_device Greg KH
  1 sibling, 1 reply; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-12  6:32 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

#### AUTHOR dtor_core@ameritech.net
#### COMMENT START
### Comments for ChangeSet
Driver core: add "driver" default device attribute that produces
             name of the driver currently bound to the device and
             allows execution of bus-specific actions for device
             and driver via bus->rebind_helper()

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
### Comments for drivers/base/interface.c
Add "driver" default device attribute.
### Comments for include/linux/device.h
Add rebind_helper method to bus_type structure.
### Comments for drivers/input/serio/serio.c
Do not create "driver": attribute as driver core will create it for us;
install serio_rebind_driver as serio_bus's rebind_helper.
#### COMMENT END

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/11 00:39:53-05:00 dtor_core@ameritech.net 
#   Driver core: add "driver" default device attribute that produces
#                name of the driver currently bound to the device and
#                allows execution of bus-specific actions for device
#                and driver via bus->rebind_helper()
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/device.h
#   2004/10/11 00:39:34-05:00 dtor_core@ameritech.net +2 -1
#   Add rebind_helper method to bus_type structure.
# 
# drivers/input/serio/serio.c
#   2004/10/11 00:39:34-05:00 dtor_core@ameritech.net +31 -36
#   Do not create "driver": attribute as driver core will create it for us;
#   install serio_rebind_driver as serio_bus's rebind_helper.
# 
# drivers/base/interface.c
#   2004/10/11 00:39:33-05:00 dtor_core@ameritech.net +30 -1
#   Add "driver" default device attribute.
# 
diff -Nru a/drivers/base/interface.c b/drivers/base/interface.c
--- a/drivers/base/interface.c	2004-10-12 01:29:06 -05:00
+++ b/drivers/base/interface.c	2004-10-12 01:29:06 -05:00
@@ -42,10 +42,39 @@
 	return n;
 }
 
-static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
+/**
+ *	driver - controls device and driver binding.
+ *
+ *	Reading from the attribute gives name of driver that is bound to
+ *	the device or "(none)". Result of writing to the attribute depends
+ *	on the bus's rebind_helper implementation and can cause device to
+ *	be disconnected or be rebound to a specific driver.
+ */
+
+static ssize_t driver_show(struct device * dev, char * buf)
+{
+	return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)");
+}
+
+static ssize_t driver_store(struct device * dev, const char * buf, size_t count)
+{
+	int retval = -ENOSYS;
+
+	if (dev->bus->rebind_helper)
+		retval = dev->bus->rebind_helper(dev, buf, count);
 
+	if (retval < 0)
+		return retval;
+
+	return count;
+}
+
+
+static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
+static DEVICE_ATTR(driver, 0644, driver_show, driver_store);
 
 struct attribute * dev_default_attrs[] = {
 	&dev_attr_detach_state.attr,
+	&dev_attr_driver.attr,
 	NULL,
 };
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	2004-10-12 01:29:06 -05:00
+++ b/drivers/input/serio/serio.c	2004-10-12 01:29:06 -05:00
@@ -246,41 +246,6 @@
 	return sprintf(buf, "%s\n", serio->name);
 }
 
-static ssize_t serio_show_driver(struct device *dev, char *buf)
-{
-	return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)");
-}
-
-static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
-{
-	struct serio *serio = to_serio_port(dev);
-	struct device_driver *drv;
-	int retval;
-
-	retval = down_interruptible(&serio_sem);
-	if (retval)
-		return retval;
-
-	retval = count;
-	if (!strncmp(buf, "none", count)) {
-		serio_disconnect_port(serio);
-	} else if (!strncmp(buf, "reconnect", count)) {
-		serio_reconnect_port(serio);
-	} else if (!strncmp(buf, "rescan", count)) {
-		serio_disconnect_port(serio);
-		serio_connect_port(serio, NULL);
-	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
-		serio_disconnect_port(serio);
-		serio_connect_port(serio, to_serio_driver(drv));
-		put_driver(drv);
-	} else {
-		retval = -EINVAL;
-	}
-
-	up(&serio_sem);
-
-	return retval;
-}
 
 static ssize_t serio_show_bind_mode(struct device *dev, char *buf)
 {
@@ -307,7 +272,6 @@
 
 static struct device_attribute serio_device_attrs[] = {
 	__ATTR(description, S_IRUGO, serio_show_description, NULL),
-	__ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver),
 	__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
 	__ATTR_NULL
 };
@@ -596,6 +560,36 @@
 	up(&serio_sem);
 }
 
+static int serio_rebind_driver(struct device *dev, const char *buf, size_t count)
+{
+	struct serio *serio = to_serio_port(dev);
+	struct device_driver *drv;
+	int retval;
+
+	retval = down_interruptible(&serio_sem);
+	if (retval)
+		return retval;
+
+	if (!strncmp(buf, "none", count)) {
+		serio_disconnect_port(serio);
+	} else if (!strncmp(buf, "reconnect", count)) {
+		serio_reconnect_port(serio);
+	} else if (!strncmp(buf, "rescan", count)) {
+		serio_disconnect_port(serio);
+		serio_connect_port(serio, NULL);
+	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
+		serio_disconnect_port(serio);
+		serio_connect_port(serio, to_serio_driver(drv));
+		put_driver(drv);
+	} else {
+		retval = -EINVAL;
+	}
+
+	up(&serio_sem);
+
+	return retval;
+}
+
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 {
 	down(&serio->drv_sem);
@@ -660,6 +654,7 @@
 
 	serio_bus.dev_attrs = serio_device_attrs;
 	serio_bus.drv_attrs = serio_driver_attrs;
+	serio_bus.rebind_helper = serio_rebind_driver;
 	bus_register(&serio_bus);
 
 	return 0;
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	2004-10-12 01:29:06 -05:00
+++ b/include/linux/device.h	2004-10-12 01:29:06 -05:00
@@ -59,7 +59,8 @@
 	struct driver_attribute	* drv_attrs;
 
 	int		(*match)(struct device * dev, struct device_driver * drv);
-	int		(*hotplug) (struct device *dev, char **envp, 
+	int		(*rebind_helper)(struct device * dev, const char * buf, size_t count);
+	int		(*hotplug) (struct device *dev, char **envp,
 				    int num_envp, char *buffer, int buffer_size);
 	int		(*suspend)(struct device * dev, u32 state);
 	int		(*resume)(struct device * dev);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 4/4] Driver core: add "bind_mode" default attribute
  2004-10-12  6:32             ` [PATCH 3/4] Driver core: add "driver" default attribute Dmitry Torokhov
@ 2004-10-12  6:33               ` Dmitry Torokhov
  0 siblings, 0 replies; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-12  6:33 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

#### AUTHOR dtor_core@ameritech.net
#### COMMENT START
### Comments for ChangeSet
Driver core: add "bind_mode" default device and driver attribute.
             Calls to device_attach() and driver_attach() will not
             bind device and driver if either one of them is in
             "manual" bind mode. Manual binding is expected to be
             handled by bus's rebind_handler()

         echo -n "manual" > /sus/bus/serio/devices/serio2/bind_mode
         echo -n "auto" > /sys/bus/serio/drivers/serio_raw/bind_mode

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
### Comments for drivers/input/serio/serio_raw.c
Move manual_bind flag from serio driver to core driver.
### Comments for drivers/base/bus.c
Do not automatically bind device and a driver if either on has
non-zero manual_bind flag.
### Comments for drivers/base/interface.c
Add bind_mode default attribute to devices and drivers.
### Comments for include/linux/device.h
Add manual_bind flags to device and device_driver structures.
### Comments for drivers/input/serio/serio.c
Do not create bind_mode device and driver attributes as they are
created autimatically by the driver core.
### Comments for include/linux/serio.h
Remove manual_bind flags from serio and serio_driver as they are
in driver core now.
#### COMMENT END

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/11 00:57:02-05:00 dtor_core@ameritech.net 
#   Driver core: add "bind_mode" default device and driver attribute.
#                Calls to device_attach() and driver_attach() will not
#                bind device and driver if either one of them is in
#                "manual" bind mode. Manual binding is expected to be
#                handled by bus's rebind_handler()
#   
#            echo -n "manual" > /sus/bus/serio/devices/serio2/bind_mode
#            echo -n "auto" > /sys/bus/serio/drivers/serio_raw/bind_mode
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/serio.h
#   2004/10/11 00:56:40-05:00 dtor_core@ameritech.net +0 -4
#   Remove manual_bind flags from serio and serio_driver as they are
#   in driver core now.
# 
# include/linux/device.h
#   2004/10/11 00:56:40-05:00 dtor_core@ameritech.net +5 -0
#   Add manual_bind flags to device and device_driver structures.
# 
# drivers/input/serio/serio_raw.c
#   2004/10/11 00:56:40-05:00 dtor_core@ameritech.net +2 -2
#   Move manual_bind flag from serio driver to core driver.
# 
# drivers/input/serio/serio.c
#   2004/10/11 00:56:40-05:00 dtor_core@ameritech.net +4 -55
#   Do not create bind_mode device and driver attributes as they are
#   created autimatically by the driver core.
# 
# drivers/base/interface.c
#   2004/10/11 00:56:40-05:00 dtor_core@ameritech.net +74 -7
#   Add bind_mode default attribute to devices and drivers.
# 
# drivers/base/bus.c
#   2004/10/11 00:56:40-05:00 dtor_core@ameritech.net +13 -7
#   Do not automatically bind device and a driver if either on has
#   non-zero manual_bind flag.
# 
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	2004-10-12 01:30:09 -05:00
+++ b/drivers/base/bus.c	2004-10-12 01:30:09 -05:00
@@ -68,9 +68,12 @@
 	up(&drv->unload_sem);
 }
 
+extern struct attribute * drv_default_attrs[];
+
 static struct kobj_type ktype_driver = {
 	.sysfs_ops	= &driver_sysfs_ops,
 	.release	= driver_release,
+	.default_attrs	= drv_default_attrs,
 };
 
 
@@ -301,9 +304,12 @@
 		return 1;
 	}
 
-	if (bus->match) {
-		list_for_each(entry, &bus->drivers.list) {
-			struct device_driver * drv = to_drv(entry);
+	if (dev->manual_bind || !bus->match)
+		return 0;
+
+	list_for_each(entry, &bus->drivers.list) {
+		struct device_driver * drv = to_drv(entry);
+		if (!drv->manual_bind) {
 			error = driver_probe_device(drv, dev);
 			if (!error)
 				/* success, driver matched */
@@ -311,8 +317,8 @@
 			if (error != -ENODEV)
 				/* driver matched but the probe failed */
 				printk(KERN_WARNING
-				    "%s: probe of %s failed with error %d\n",
-				    drv->name, dev->bus_id, error);
+					"%s: probe of %s failed with error %d\n",
+					drv->name, dev->bus_id, error);
 		}
 	}
 
@@ -338,12 +344,12 @@
 	struct list_head * entry;
 	int error;
 
-	if (!bus->match)
+	if (drv->manual_bind || !bus->match)
 		return;
 
 	list_for_each(entry, &bus->devices.list) {
 		struct device * dev = container_of(entry, struct device, bus_list);
-		if (!dev->driver) {
+		if (!dev->driver && !dev->manual_bind) {
 			error = driver_probe_device(drv, dev);
 			if (error && (error != -ENODEV))
 				/* driver matched but the probe failed */
diff -Nru a/drivers/base/interface.c b/drivers/base/interface.c
--- a/drivers/base/interface.c	2004-10-12 01:30:09 -05:00
+++ b/drivers/base/interface.c	2004-10-12 01:30:09 -05:00
@@ -1,6 +1,6 @@
 /*
  * drivers/base/interface.c - common driverfs interface that's exported to
- * 	the world for all devices.
+ * 	the world for all devices and drivers.
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
@@ -15,6 +15,35 @@
 #include <linux/string.h>
 
 /**
+ *	bind_mode - control the binding mode for the device.
+ *
+ *	When set to "auto" driver core will try to automatically bind the
+ *	device once appropriate driver becomes available. When bind mode
+ *	is "manual" intervention from userspace is required.
+ */
+
+static ssize_t dev_bind_mode_show(struct device * dev, char * buf)
+{
+	return sprintf(buf, "%s\n", dev->manual_bind ? "manual" : "auto");
+}
+
+static ssize_t dev_bind_mode_store(struct device * dev, const char * buf, size_t count)
+{
+	int retval = count;
+
+	if (!strncmp(buf, "manual", count)) {
+		dev->manual_bind = 1;
+	} else if (!strncmp(buf, "auto", count)) {
+		dev->manual_bind = 0;
+	} else {
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+
+/**
  *	detach_state - control the default power state for the device.
  *
  *	This is the state the device enters when it's driver module is
@@ -27,12 +56,12 @@
  *	driver's suspend method.
  */
 
-static ssize_t detach_show(struct device * dev, char * buf)
+static ssize_t dev_detach_show(struct device * dev, char * buf)
 {
 	return sprintf(buf, "%u\n", dev->detach_state);
 }
 
-static ssize_t detach_store(struct device * dev, const char * buf, size_t n)
+static ssize_t dev_detach_store(struct device * dev, const char * buf, size_t n)
 {
 	u32 state;
 	state = simple_strtoul(buf, NULL, 10);
@@ -51,12 +80,12 @@
  *	be disconnected or be rebound to a specific driver.
  */
 
-static ssize_t driver_show(struct device * dev, char * buf)
+static ssize_t dev_driver_show(struct device * dev, char * buf)
 {
 	return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)");
 }
 
-static ssize_t driver_store(struct device * dev, const char * buf, size_t count)
+static ssize_t dev_driver_store(struct device * dev, const char * buf, size_t count)
 {
 	int retval = -ENOSYS;
 
@@ -70,11 +99,49 @@
 }
 
 
-static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
-static DEVICE_ATTR(driver, 0644, driver_show, driver_store);
+static DEVICE_ATTR(bind_mode, 0644, dev_bind_mode_show, dev_bind_mode_store);
+static DEVICE_ATTR(detach_state, 0644, dev_detach_show, dev_detach_store);
+static DEVICE_ATTR(driver, 0644, dev_driver_show, dev_driver_store);
 
 struct attribute * dev_default_attrs[] = {
+	&dev_attr_bind_mode.attr,
 	&dev_attr_detach_state.attr,
 	&dev_attr_driver.attr,
 	NULL,
 };
+
+/**
+ *	bind_mode - control the binding mode for the driver.
+ *
+ *	When set to "auto" driver core will try to automatically bind the
+ *	driver once appropriate device becomes available. When bind mode
+ *	is "manual" intervention from userspace is required.
+ */
+
+static ssize_t drv_bind_mode_show(struct device_driver * drv, char * buf)
+{
+	return sprintf(buf, "%s\n", drv->manual_bind ? "manual" : "auto");
+}
+
+static ssize_t drv_bind_mode_store(struct device_driver * drv, const char * buf, size_t count)
+{
+	int retval = count;
+
+	if (!strncmp(buf, "manual", count)) {
+		drv->manual_bind = 1;
+	} else if (!strncmp(buf, "auto", count)) {
+		drv->manual_bind = 0;
+	} else {
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+static DRIVER_ATTR(bind_mode, 0644, drv_bind_mode_show, drv_bind_mode_store);
+
+struct attribute * drv_default_attrs[] = {
+	&driver_attr_bind_mode.attr,
+	NULL,
+};
+
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	2004-10-12 01:30:09 -05:00
+++ b/drivers/input/serio/serio.c	2004-10-12 01:30:09 -05:00
@@ -92,7 +92,7 @@
 	struct serio_driver *drv;
 
 	list_for_each_entry(drv, &serio_driver_list, node)
-		if (!drv->manual_bind)
+		if (!drv->driver.manual_bind)
 			if (serio_bind_driver(serio, drv))
 				break;
 }
@@ -246,33 +246,8 @@
 	return sprintf(buf, "%s\n", serio->name);
 }
 
-
-static ssize_t serio_show_bind_mode(struct device *dev, char *buf)
-{
-	struct serio *serio = to_serio_port(dev);
-	return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto");
-}
-
-static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count)
-{
-	struct serio *serio = to_serio_port(dev);
-	int retval;
-
-	retval = count;
-	if (!strncmp(buf, "manual", count)) {
-		serio->manual_bind = 1;
-	} else if (!strncmp(buf, "auto", count)) {
-		serio->manual_bind = 0;
-	} else {
-		retval = -EINVAL;
-	}
-
-	return retval;
-}
-
 static struct device_attribute serio_device_attrs[] = {
 	__ATTR(description, S_IRUGO, serio_show_description, NULL),
-	__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
 	__ATTR_NULL
 };
 
@@ -341,7 +316,7 @@
 
 	if (drv)
 		serio_bind_driver(serio, drv);
-	else if (!serio->manual_bind)
+	else if (!serio->dev.manual_bind)
 		serio_find_driver(serio);
 
 	/* Ok, now bind children, if any */
@@ -353,7 +328,7 @@
 
 		serio_create_port(serio);
 
-		if (!serio->manual_bind) {
+		if (!serio->dev.manual_bind) {
 			/*
 			 * With children we just _prefer_ passed in driver,
 			 * but we will try other options in case preferred
@@ -475,34 +450,8 @@
 	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
 }
 
-static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf)
-{
-	struct serio_driver *serio_drv = to_serio_driver(drv);
-	return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto");
-}
-
-static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count)
-{
-	struct serio_driver *serio_drv = to_serio_driver(drv);
-	int retval;
-
-	retval = count;
-	if (!strncmp(buf, "manual", count)) {
-		serio_drv->manual_bind = 1;
-	} else if (!strncmp(buf, "auto", count)) {
-		serio_drv->manual_bind = 0;
-	} else {
-		retval = -EINVAL;
-	}
-
-	return retval;
-}
-
-
 static struct driver_attribute serio_driver_attrs[] = {
 	__ATTR(description, S_IRUGO, serio_driver_show_description, NULL),
-	__ATTR(bind_mode, S_IWUSR | S_IRUGO,
-		serio_driver_show_bind_mode, serio_driver_set_bind_mode),
 	__ATTR_NULL
 };
 
@@ -517,7 +466,7 @@
 	drv->driver.bus = &serio_bus;
 	driver_register(&drv->driver);
 
-	if (drv->manual_bind)
+	if (drv->driver.manual_bind)
 		goto out;
 
 start_over:
diff -Nru a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
--- a/drivers/input/serio/serio_raw.c	2004-10-12 01:30:09 -05:00
+++ b/drivers/input/serio/serio_raw.c	2004-10-12 01:30:09 -05:00
@@ -365,14 +365,14 @@
 
 static struct serio_driver serio_raw_drv = {
 	.driver		= {
-		.name	= "serio_raw",
+		.name		= "serio_raw",
+		.manual_bind	= 1,
 	},
 	.description	= DRIVER_DESC,
 	.interrupt	= serio_raw_interrupt,
 	.connect	= serio_raw_connect,
 	.reconnect	= serio_raw_reconnect,
 	.disconnect	= serio_raw_disconnect,
-	.manual_bind	= 1,
 };
 
 int __init serio_raw_init(void)
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	2004-10-12 01:30:09 -05:00
+++ b/include/linux/device.h	2004-10-12 01:30:09 -05:00
@@ -103,6 +103,8 @@
 	char			* name;
 	struct bus_type		* bus;
 
+	unsigned int		manual_bind;
+
 	struct semaphore	unload_sem;
 	struct kobject		kobj;
 	struct list_head	devices;
@@ -265,6 +267,9 @@
 	struct bus_type	* bus;		/* type of bus device is on */
 	struct device_driver *driver;	/* which driver has allocated this
 					   device */
+	unsigned int manual_bind;	/* indicates whether the core will
+					   try to find a driver for the
+					   device automatically */
 	void		*driver_data;	/* data private to the driver */
 	void		*platform_data;	/* Platform specific data (e.g. ACPI,
 					   BIOS data relevant to device) */
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	2004-10-12 01:30:09 -05:00
+++ b/include/linux/serio.h	2004-10-12 01:30:09 -05:00
@@ -27,8 +27,6 @@
 	char name[32];
 	char phys[32];
 
-	unsigned int manual_bind;
-
 	unsigned short idbus;
 	unsigned short idvendor;
 	unsigned short idproduct;
@@ -57,8 +55,6 @@
 struct serio_driver {
 	void *private;
 	char *description;
-
-	unsigned int manual_bind;
 
 	void (*write_wakeup)(struct serio *);
 	irqreturn_t (*interrupt)(struct serio *, unsigned char,

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Driver core change request
  2004-10-12  6:29       ` Dmitry Torokhov
  2004-10-12  6:31         ` [PATCH 1/4] Driver core: export device_attach Dmitry Torokhov
@ 2004-10-21  7:05         ` Dmitry Torokhov
  2004-10-21 14:50           ` Greg KH
  1 sibling, 1 reply; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-21  7:05 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

On Tuesday 12 October 2004 01:29 am, Dmitry Torokhov wrote:
> For now I added:
> 
> - "driver" default device attribute that produces name of currently bound
>   driver uppon read.
> - bus->rebind_handler method that is called when someone writes to "driver"
>   attribute and allows to perform bunctions like disconnecting device or
>   rebinding it to alternative driver in bus-specific way.
> - "bind_mode" default device and driver attributes that can be "auto" or
>   "manual". When device or driver marked as manual bind device_attach()
>   and driver_attach() will ignore them. They are expected to be bound by
>   bus->rebind_handler (via driver_probe_device()).
> 
> I also renamed bus_match to driver_probe_device() and exported it, along
> with device_attach and driver_attach.
> 
> Please let me know if its acceptable.
> 

Greg,

Sorry for bothering you but cold you tell me if you are staisfied with the
patches or I need to look for some alternative. As an example of usage
please find my working copy of serio.c below.

Thanks! 

-- 
Dmitry

/*
 *  The Serio abstraction module
 *
 *  Copyright (c) 1999-2004 Vojtech Pavlik
 *  Copyright (c) 2004 Dmitry Torokhov
 *  Copyright (c) 2003 Daniele Bellucci
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 */

#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/suspend.h>
#include <linux/slab.h>

MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
MODULE_LICENSE("GPL");

EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(__serio_unregister_port_delayed);
EXPORT_SYMBOL(serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
EXPORT_SYMBOL(serio_rescan);
EXPORT_SYMBOL(serio_reconnect);

/*
 * serio_sem protects entire serio subsystem and is taken every time
 * serio port or driver registrered or unregistered.
 */
static DECLARE_MUTEX(serio_sem);

static LIST_HEAD(serio_list);

struct bus_type serio_bus = {
	.name =	"serio",
};

static void serio_add_port(struct serio *serio);
static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);

/*
 * Basic serio -> driver core mappings
 */

static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
{
	down_write(&serio_bus.subsys.rwsem);
	driver_probe_device(&drv->driver, &serio->dev);
	up_write(&serio_bus.subsys.rwsem);
}

static void serio_release_driver(struct serio *serio)
{
	down_write(&serio_bus.subsys.rwsem);
	device_release_driver(&serio->dev);
	up_write(&serio_bus.subsys.rwsem);
}

static void serio_find_driver(struct serio *serio)
{
	down_write(&serio_bus.subsys.rwsem);
	device_attach(&serio->dev);
	up_write(&serio_bus.subsys.rwsem);
}

/*
 * Serio event processing.
 */

struct serio_event {
	int type;
	struct serio *serio;
	struct module *owner;
	struct list_head node;
};

enum serio_event_type {
	SERIO_RESCAN,
	SERIO_RECONNECT,
	SERIO_REGISTER_PORT,
	SERIO_UNREGISTER_PORT,
};

static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED;	/* protects serio_event_list */
static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited);
static int serio_pid;

static void serio_queue_event(struct serio *serio, struct module *owner, int event_type)
{
	unsigned long flags;
	struct serio_event *event;

	spin_lock_irqsave(&serio_event_lock, flags);

	if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
		__module_get(owner);

		event->type = event_type;
		event->serio = serio;
		event->owner = owner;

		list_add_tail(&event->node, &serio_event_list);
		wake_up(&serio_wait);
	} else
		printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type);

	spin_unlock_irqrestore(&serio_event_lock, flags);
}

static struct serio_event *serio_get_event(void)
{
	struct serio_event *event = NULL;
	struct list_head *node;
	unsigned long flags;

	spin_lock_irqsave(&serio_event_lock, flags);

	if (!list_empty(&serio_event_list)) {
		node = serio_event_list.next;
		event = container_of(node, struct serio_event, node);
		list_del_init(node);
	}

	spin_unlock_irqrestore(&serio_event_lock, flags);

	return event;
}

static void serio_handle_events(void)
{
	struct serio_event *event;

	down(&serio_sem);

	while ((event = serio_get_event())) {

		switch (event->type) {
			case SERIO_REGISTER_PORT :
				serio_add_port(event->serio);
				serio_find_driver(event->serio);
				break;

			case SERIO_UNREGISTER_PORT :
				serio_disconnect_port(event->serio);
				serio_destroy_port(event->serio);
				break;

			case SERIO_RECONNECT :
				serio_reconnect_port(event->serio);
				break;

			case SERIO_RESCAN :
				serio_disconnect_port(event->serio);
				serio_find_driver(event->serio);
				break;
			default:
				break;
		}

		module_put(event->owner);
		kfree(event);
	}

	up(&serio_sem);
}

/*
 * Remove all events that have been submitted for a gicen serio port.
 */
static void serio_remove_pending_events(struct serio *serio)
{
	struct list_head *node, *next;
	struct serio_event *event;
	unsigned long flags;

	spin_lock_irqsave(&serio_event_lock, flags);

	list_for_each_safe(node, next, &serio_event_list) {
		event = list_entry(node, struct serio_event, node);
		if (event->serio == serio) {
			list_del_init(node);
			kfree(event);
		}
	}

	spin_unlock_irqrestore(&serio_event_lock, flags);
}

/*
 * Destroy child serio port (if any) that has not been fully registered yet.
 *
 * Note that we rely on the fact that port can have only one child and therefore
 * only one child registration request can be pending. Additionally, children
 * are registered by driver's connect() handler so there can't be a grandchild
 * pending registration together with a child.
 */
static struct serio *serio_get_pending_child(struct serio *parent)
{
	struct serio_event *event;
	struct serio *serio = NULL;
	unsigned long flags;

	spin_lock_irqsave(&serio_event_lock, flags);

	list_for_each_entry(event, &serio_event_list, node) {
		if (event->type == SERIO_REGISTER_PORT && event->serio->parent == parent) {
			serio = event->serio;
			break;
		}
	}

	spin_unlock_irqrestore(&serio_event_lock, flags);
	return serio;
}

static int serio_thread(void *nothing)
{
	lock_kernel();
	daemonize("kseriod");
	allow_signal(SIGTERM);

	do {
		serio_handle_events();
		wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
		if (current->flags & PF_FREEZE)
			refrigerator(PF_FREEZE);
	} while (!signal_pending(current));

	printk(KERN_DEBUG "serio: kseriod exiting\n");

	unlock_kernel();
	complete_and_exit(&serio_exited, 0);
}


/*
 * Serio port operations
 */

static ssize_t serio_show_description(struct device *dev, char *buf)
{
	struct serio *serio = to_serio_port(dev);
	return sprintf(buf, "%s\n", serio->name);
}

static struct device_attribute serio_device_attrs[] = {
	__ATTR(description, S_IRUGO, serio_show_description, NULL),
	__ATTR_NULL
};


static void serio_release_port(struct device *dev)
{
	struct serio *serio = to_serio_port(dev);

printk(KERN_INFO "serio: releasing %s\n", serio->name);
	kfree(serio);
	module_put(THIS_MODULE);
}

/*
 * Prepare serio port for registration.
 */
static void serio_init_port(struct serio *serio)
{
	static atomic_t serio_no = ATOMIC_INIT(0);

	__module_get(THIS_MODULE);

	spin_lock_init(&serio->lock);
	init_MUTEX(&serio->drv_sem);
	device_initialize(&serio->dev);
	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),
		 "serio%d", atomic_inc_return(&serio_no) - 1);
	serio->dev.bus = &serio_bus;
	serio->dev.release = serio_release_port;
	if (serio->parent)
		serio->dev.parent = &serio->parent->dev;
}

/*
 * Complete serio port registration.
 * Driver core will attempt to find appropriate driver for the port.
 */
static void serio_add_port(struct serio *serio)
{
	if (serio->parent) {
		serio_pause_rx(serio->parent);
		serio->parent->child = serio;
		serio_continue_rx(serio->parent);
	}

	list_add_tail(&serio->node, &serio_list);
	device_add(&serio->dev);
	serio->registered = 1;
}

/*
 * serio_destroy_port() completes deregistration process and removes
 * port from the system.
 */
static void serio_destroy_port(struct serio *serio)
{
	struct serio *child;

printk(KERN_INFO "serio: destroying port %s, cnt: %d\n", serio->name,  atomic_read(&serio->dev.kobj.kref.refcount));
	child = serio_get_pending_child(serio);
	if (child) {
		serio_remove_pending_events(child);
		put_device(&child->dev);
	}

	if (serio->parent) {
		serio_pause_rx(serio->parent);
		serio->parent->child = NULL;
		serio->parent = NULL;
		serio_continue_rx(serio->parent);
	}

	if (serio->registered) {
printk(KERN_INFO "serio: destroying port %s (device_del)\n", serio->name);
		device_del(&serio->dev);
		list_del_init(&serio->node);
		serio->registered = 0;
	}

	serio_remove_pending_events(serio);
printk(KERN_INFO "serio: destroying port %s (put_device)\n", serio->name);
	put_device(&serio->dev);
}

/*
 * Reconnect serio port and all its children (re-initialize attached devices)
 */
static void serio_reconnect_port(struct serio *serio)
{
	do {
		if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
			serio_disconnect_port(serio);
			serio_find_driver(serio);
			/* Ok, old children are now gone, we are done */
			break;
		}
		serio = serio->child;
	} while (serio);
}

/*
 * serio_disconnect_port() unbinds a port from its driver. As a side effect
 * all child ports are unbound and destroyed.
 */
static void serio_disconnect_port(struct serio *serio)
{
	struct serio *s, *parent;

printk(KERN_INFO "serio: disconnecting port %s\n", serio->name);

	if (serio->child) {
		/*
		 * Children ports should be disconnected and destroyed
		 * first, staring with the leaf one, since we don't want
		 * to do recursion
		 */
		for (s = serio; s->child; s = s->child)
			/* empty */;

		do {
			parent = s->parent;

printk(KERN_INFO "serio: releasing driver on child port %s\n", s->name);
			serio_release_driver(s);
printk(KERN_INFO "serio: destroying port %s\n", s->name);
			serio_destroy_port(s);
		} while ((s = parent) != serio);
	}

	/*
	 * Ok, no children left, now disconnect this port
	 */
printk(KERN_INFO "serio: releasing driver on port %s\n", serio->name);
	serio_release_driver(serio);
}

void serio_rescan(struct serio *serio)
{
	serio_queue_event(serio, NULL, SERIO_RESCAN);
}

void serio_reconnect(struct serio *serio)
{
	serio_queue_event(serio, NULL, SERIO_RECONNECT);
}

/*
 * Submits register request to kseriod for subsequent execution.
 * Note that port registration is always asynchronous.
 */
void __serio_register_port(struct serio *serio, struct module *owner)
{
	serio_init_port(serio);
	serio_queue_event(serio, owner, SERIO_REGISTER_PORT);
}

/*
 * Synchronously unregisters serio port.
 */
void serio_unregister_port(struct serio *serio)
{
	down(&serio_sem);
	serio_disconnect_port(serio);
	serio_destroy_port(serio);
	up(&serio_sem);
}

/*
 * Submits unregister request to kseriod for subsequent execution.
 * Can be used when it is not obvious whether the serio_sem is
 * taken or not and when delayed execution is feasible.
 */
void __serio_unregister_port_delayed(struct serio *serio, struct module *owner)
{
	serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT);
}


/*
 * Serio driver operations
 */

static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf)
{
	struct serio_driver *driver = to_serio_driver(drv);
	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
}

static struct driver_attribute serio_driver_attrs[] = {
	__ATTR(description, S_IRUGO, serio_driver_show_description, NULL),
	__ATTR_NULL
};

static int serio_driver_probe(struct device *dev)
{
	struct serio *serio = to_serio_port(dev);
	struct serio_driver *drv = to_serio_driver(dev->driver);

printk(KERN_INFO "serio: driver probe for %s and %s\n", drv->driver.name, serio->name);
	drv->connect(serio, drv);
	return serio->drv ? 0 : -ENODEV;
}

static int serio_driver_remove(struct device *dev)
{
	struct serio *serio = to_serio_port(dev);
	struct serio_driver *drv = to_serio_driver(dev->driver);

printk(KERN_INFO "serio: driver remove for %s and %s\n", drv->driver.name, serio->name);
	drv->disconnect(serio);
	return 0;
}

void serio_register_driver(struct serio_driver *drv)
{
	down(&serio_sem);

	drv->driver.bus = &serio_bus;
	drv->driver.probe = serio_driver_probe;
	drv->driver.remove = serio_driver_remove;
	driver_register(&drv->driver);

	up(&serio_sem);
}

void serio_unregister_driver(struct serio_driver *drv)
{
	struct serio *serio;

	down(&serio_sem);
	drv->driver.manual_bind = 1;	/* so serio_find_driver ignores it */

start_over:
	list_for_each_entry(serio, &serio_list, node) {
		if (serio->drv == drv) {
			serio_disconnect_port(serio);
			serio_find_driver(serio);
			/* we could've deleted some ports, restart */
			goto start_over;
		}
	}

	driver_unregister(&drv->driver);
	up(&serio_sem);
}

static int serio_rebind_driver(struct device *dev, const char *buf, size_t count)
{
	struct serio *serio = to_serio_port(dev);
	struct device_driver *drv;
	int retval;

	retval = down_interruptible(&serio_sem);
	if (retval)
		return retval;

	if (!strncmp(buf, "none", count)) {
		serio_disconnect_port(serio);
	} else if (!strncmp(buf, "reconnect", count)) {
		serio_reconnect_port(serio);
	} else if (!strncmp(buf, "rescan", count)) {
		serio_disconnect_port(serio);
		serio_find_driver(serio);
	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
		serio_disconnect_port(serio);
		serio_bind_driver(serio, to_serio_driver(drv));
		put_driver(drv);
	} else {
		retval = -EINVAL;
	}

	up(&serio_sem);

	return retval;
}

static int serio_bus_match(struct device *dev, struct device_driver *drv)
{
	/*
	 * For now we match everything as real checks are done in
	 * connect methods.
	 */
	return 1;
}

static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
	down(&serio->drv_sem);
	serio_pause_rx(serio);
	serio->drv = drv;
	serio_continue_rx(serio);
	up(&serio->drv_sem);
}

/* called from serio_driver->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_driver *drv)
{
	serio_set_drv(serio, drv);

	if (serio->open && serio->open(serio)) {
		serio_set_drv(serio, NULL);
		return -1;
	}
	return 0;
}

/* called from serio_driver->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio)
{
	if (serio->close)
		serio->close(serio);

	serio_set_drv(serio, NULL);
}

irqreturn_t serio_interrupt(struct serio *serio,
		unsigned char data, unsigned int dfl, struct pt_regs *regs)
{
	unsigned long flags;
	irqreturn_t ret = IRQ_NONE;

	spin_lock_irqsave(&serio->lock, flags);

        if (likely(serio->drv)) {
                ret = serio->drv->interrupt(serio, data, dfl, regs);
	} else {
		if (!dfl) {
			if ((serio->type != SERIO_8042 &&
			     serio->type != SERIO_8042_XL) || (data == 0xaa)) {
				serio_rescan(serio);
				ret = IRQ_HANDLED;
			}
		}
	}

	spin_unlock_irqrestore(&serio->lock, flags);

	return ret;
}

static int __init serio_init(void)
{
	if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
		printk(KERN_ERR "serio: Failed to start kseriod\n");
		return -1;
	}

	serio_bus.dev_attrs = serio_device_attrs;
	serio_bus.drv_attrs = serio_driver_attrs;
	serio_bus.match = serio_bus_match;
	serio_bus.rebind_helper = serio_rebind_driver;
	bus_register(&serio_bus);

	return 0;
}

static void __exit serio_exit(void)
{
	bus_unregister(&serio_bus);
	kill_proc(serio_pid, SIGTERM, 1);
	wait_for_completion(&serio_exited);
}

module_init(serio_init);
module_exit(serio_exit);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Driver core change request
  2004-10-21  7:05         ` Driver core change request Dmitry Torokhov
@ 2004-10-21 14:50           ` Greg KH
  0 siblings, 0 replies; 15+ messages in thread
From: Greg KH @ 2004-10-21 14:50 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Patrick Mochel

On Thu, Oct 21, 2004 at 02:05:40AM -0500, Dmitry Torokhov wrote:
> On Tuesday 12 October 2004 01:29 am, Dmitry Torokhov wrote:
> > For now I added:
> > 
> > - "driver" default device attribute that produces name of currently bound
> >   driver uppon read.
> > - bus->rebind_handler method that is called when someone writes to "driver"
> >   attribute and allows to perform bunctions like disconnecting device or
> >   rebinding it to alternative driver in bus-specific way.
> > - "bind_mode" default device and driver attributes that can be "auto" or
> >   "manual". When device or driver marked as manual bind device_attach()
> >   and driver_attach() will ignore them. They are expected to be bound by
> >   bus->rebind_handler (via driver_probe_device()).
> > 
> > I also renamed bus_match to driver_probe_device() and exported it, along
> > with device_attach and driver_attach.
> > 
> > Please let me know if its acceptable.
> > 
> 
> Greg,
> 
> Sorry for bothering you but cold you tell me if you are staisfied with the
> patches or I need to look for some alternative. As an example of usage
> please find my working copy of serio.c below.

I like part of them :)

But I'm still swamped with syncing up with Linus's tree, but should be
able to get to these later this afternoon.  I haven't forgotten about
these, they are still in my todo queue.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] Driver core: export device_attach
  2004-10-12  6:31         ` [PATCH 1/4] Driver core: export device_attach Dmitry Torokhov
  2004-10-12  6:31           ` [PATCH 2/4] Driver core: add driver_probe_device Dmitry Torokhov
@ 2004-10-29 16:37           ` Greg KH
  1 sibling, 0 replies; 15+ messages in thread
From: Greg KH @ 2004-10-29 16:37 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Patrick Mochel

On Tue, Oct 12, 2004 at 01:31:04AM -0500, Dmitry Torokhov wrote:
> #### AUTHOR dtor_core@ameritech.net
> #### COMMENT START
> ### Comments for ChangeSet
> Driver core: make device_attach() global and export it and
>              driver_attach() so subsystems can have finer
>              control over binding process.

Applied, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Driver core: add driver_probe_device
  2004-10-12  6:31           ` [PATCH 2/4] Driver core: add driver_probe_device Dmitry Torokhov
  2004-10-12  6:32             ` [PATCH 3/4] Driver core: add "driver" default attribute Dmitry Torokhov
@ 2004-10-29 16:37             ` Greg KH
  2004-10-29 18:24               ` Dmitry Torokhov
  1 sibling, 1 reply; 15+ messages in thread
From: Greg KH @ 2004-10-29 16:37 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Patrick Mochel

On Tue, Oct 12, 2004 at 01:31:36AM -0500, Dmitry Torokhov wrote:
> #### AUTHOR dtor_core@ameritech.net
> #### COMMENT START
> ### Comments for ChangeSet
> Driver core: rename bus_match into driver_probe_device and export
>              it so subsystems can bind an individual device to a
>              specific driver without getting involved with driver
>              core internals.

Applied, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Driver core: add driver_probe_device
  2004-10-29 16:37             ` [PATCH 2/4] Driver core: add driver_probe_device Greg KH
@ 2004-10-29 18:24               ` Dmitry Torokhov
  2004-10-29 18:32                 ` Greg KH
  0 siblings, 1 reply; 15+ messages in thread
From: Dmitry Torokhov @ 2004-10-29 18:24 UTC (permalink / raw)
  To: Greg KH; +Cc: LKML, Patrick Mochel

On Friday 29 October 2004 11:37 am, Greg KH wrote:
> On Tue, Oct 12, 2004 at 01:31:36AM -0500, Dmitry Torokhov wrote:
> > #### AUTHOR dtor_core@ameritech.net
> > #### COMMENT START
> > ### Comments for ChangeSet
> > Driver core: rename bus_match into driver_probe_device and export
> >              it so subsystems can bind an individual device to a
> >              specific driver without getting involved with driver
> >              core internals.
> 
> Applied, thanks.
> 

Greg,

What about "bind_mode" device and driver attributes? If you are not going
to apply them then I need to rework driver_probe_device to not call 
bus->match() function. The reason is that if bind_mode is not in the core
then I need to check these attributes in serio's bus match function, but
then I will not be able to use driver_probe_device to force binding when
user requests it. And if I don't check bind_mode in serio_bus_match then
I will have to do all driver/device mathing by hand which I wanted to
avoid in the first place.

Please let me know.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/4] Driver core: add driver_probe_device
  2004-10-29 18:24               ` Dmitry Torokhov
@ 2004-10-29 18:32                 ` Greg KH
  0 siblings, 0 replies; 15+ messages in thread
From: Greg KH @ 2004-10-29 18:32 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: LKML, Patrick Mochel

On Fri, Oct 29, 2004 at 01:24:21PM -0500, Dmitry Torokhov wrote:
> On Friday 29 October 2004 11:37 am, Greg KH wrote:
> > On Tue, Oct 12, 2004 at 01:31:36AM -0500, Dmitry Torokhov wrote:
> > > #### AUTHOR dtor_core@ameritech.net
> > > #### COMMENT START
> > > ### Comments for ChangeSet
> > > Driver core: rename bus_match into driver_probe_device and export
> > >              it so subsystems can bind an individual device to a
> > >              specific driver without getting involved with driver
> > >              core internals.
> > 
> > Applied, thanks.
> > 
> 
> Greg,
> 
> What about "bind_mode" device and driver attributes? If you are not going
> to apply them then I need to rework driver_probe_device to not call 
> bus->match() function.

Hm, I'm not going to apply them, but haven't written that email yet,
sorry.

Is things now broken with only these 2 patches applied?

> The reason is that if bind_mode is not in the core
> then I need to check these attributes in serio's bus match function, but
> then I will not be able to use driver_probe_device to force binding when
> user requests it. And if I don't check bind_mode in serio_bus_match then
> I will have to do all driver/device mathing by hand which I wanted to
> avoid in the first place.

Heh, I understand.  I like the ideas of your next patches, but just not
the implementation.

I really like the "driver" part in the device.  But not as a file, let's
make it a symlink back to the driver that is bound to the device at that
point in time.  This makes it just like the other symlinks in the sysfs
tree.

But if we do that, we still don't have a way to implement what you are
really trying to do (and it breaks your code as you already have a
driver file.)  I'll work on what I propose instead in my next message
(will be a few hours, have real work to do for a bit, sorry...)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2004-10-29 18:49 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-10-07  4:54 Driver core change request Dmitry Torokhov
2004-10-07 21:40 ` Greg KH
2004-10-08  2:59   ` Dmitry Torokhov
2004-10-08 21:48     ` Greg KH
2004-10-12  6:29       ` Dmitry Torokhov
2004-10-12  6:31         ` [PATCH 1/4] Driver core: export device_attach Dmitry Torokhov
2004-10-12  6:31           ` [PATCH 2/4] Driver core: add driver_probe_device Dmitry Torokhov
2004-10-12  6:32             ` [PATCH 3/4] Driver core: add "driver" default attribute Dmitry Torokhov
2004-10-12  6:33               ` [PATCH 4/4] Driver core: add "bind_mode" " Dmitry Torokhov
2004-10-29 16:37             ` [PATCH 2/4] Driver core: add driver_probe_device Greg KH
2004-10-29 18:24               ` Dmitry Torokhov
2004-10-29 18:32                 ` Greg KH
2004-10-29 16:37           ` [PATCH 1/4] Driver core: export device_attach Greg KH
2004-10-21  7:05         ` Driver core change request Dmitry Torokhov
2004-10-21 14:50           ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).