# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.560 -> 1.561
# drivers/usb/Config.help 1.11 -> 1.12
# include/linux/usb.h 1.29 -> 1.30
# drivers/usb/core/usb.c 1.46 -> 1.47
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/04/25 [EMAIL PROTECTED] 1.561
# added CONFIG_USB_DYNAMIC_MINORS support to the USB core
#
# Here's a patch that finishes off my previous patch that enabled us to
# use less than 16 minor numbers per USB device that uses the USB major
# number. This patch allows all such devices to share all 256 minor
# numbers at once, much like the usbserial core shares the USB serial
# major with all usb-serial drivers. This also solves Oliver's problem of
# having 30 printers :)
# --------------------------------------------
#
diff -Nru a/drivers/usb/Config.help b/drivers/usb/Config.help
--- a/drivers/usb/Config.help Thu Apr 25 16:26:56 2002
+++ b/drivers/usb/Config.help Thu Apr 25 16:26:56 2002
@@ -69,3 +69,11 @@
If you say N here, these conditions will cause warning messages
about USB bandwidth usage to be logged and some devices or
drivers may not work correctly.
+
+CONFIG_USB_DYNAMIC_MINORS
+ If you say Y here, the USB subsystem will use dynamic minor
+ allocation for any device that uses the USB major number.
+ This means that you can have more than 16 of a single type
+ of device (like USB printers).
+
+ If you are unsure about this, say N here.
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c Thu Apr 25 16:26:56 2002
+++ b/drivers/usb/core/usb.c Thu Apr 25 16:26:57 2002
@@ -11,6 +11,7 @@
more docs, etc)
* (C) Copyright Yggdrasil Computing, Inc. 2000
* (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
@@ -59,7 +60,47 @@
devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
-static struct usb_driver *usb_minors[256];
+#define MAX_USB_MINORS 256
+static struct usb_driver *usb_minors[MAX_USB_MINORS];
+static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
+
+static int usb_register_minors (struct usb_driver *driver, int num_minors, int
+start_minor)
+{
+ int i;
+
+ dbg("registering %d minors, starting at %d", num_minors, start_minor);
+
+ if (start_minor + num_minors >= MAX_USB_MINORS)
+ return -EINVAL;
+
+ spin_lock (&minor_lock);
+ for (i = start_minor; i < (start_minor + num_minors); ++i)
+ if (usb_minors[i]) {
+ spin_unlock (&minor_lock);
+ err("minor %d is already in use, error registering %s driver",
+ i, driver->name);
+ return -EINVAL;
+ }
+
+ for (i = start_minor; i < (start_minor + num_minors); ++i)
+ usb_minors[i] = driver;
+
+ spin_unlock (&minor_lock);
+ return 0;
+}
+
+static void usb_deregister_minors (struct usb_driver *driver, int num_minors, int
+start_minor)
+{
+ int i;
+
+ dbg ("%s is removing %d minors starting at %d", driver->name,
+ num_minors, start_minor);
+
+ spin_lock (&minor_lock);
+ for (i = start_minor; i < (start_minor + num_minors); ++i)
+ usb_minors[i] = NULL;
+ spin_unlock (&minor_lock);
+}
/**
* usb_register - register a USB driver
@@ -72,18 +113,15 @@
*/
int usb_register(struct usb_driver *new_driver)
{
- int i;
-
+ int retval = 0;
+
+#ifndef CONFIG_USB_DYNAMIC_MINORS
if (new_driver->fops != NULL) {
- for (i = new_driver->minor; i < new_driver->minor +
new_driver->num_minors; ++i) {
- if (usb_minors[i]) {
- err("error registering %s driver", new_driver->name);
- return -EINVAL;
- }
- }
- for (i = new_driver->minor; i < new_driver->minor +
new_driver->num_minors; ++i)
- usb_minors[i] = new_driver;
+ retval = usb_register_minors (new_driver, new_driver->num_minors,
+new_driver->minor);
+ if (retval)
+ return retval;
}
+#endif
info("registered new driver %s", new_driver->name);
@@ -96,9 +134,94 @@
usbfs_update_special();
- return 0;
+ return retval;
}
+
+/**
+ * usb_register_dev - register a USB device, and ask for a minor number
+ * @new_driver: USB operations for the driver
+ * @num_minors: number of minor numbers requested for this device
+ * @start_minor: place to put the new starting minor number
+ *
+ * Used to ask the USB core for a new minor number for a device that has
+ * just showed up. This is used to dynamically allocate minor numbers
+ * from the pool of USB reserved minor numbers.
+ *
+ * This should be called by all drivers that use the USB major number.
+ * This only returns a good value of CONFIG_USB_DYNAMIC_MINORS is
+ * selected by the user.
+ *
+ * usb_deregister_dev() should be called when the driver is done with
+ * the minor numbers given out by this function.
+ *
+ * Returns a negative error code on failure and 0 on success, alone with
+ * a value that the driver should use in start_minor.
+ */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+int usb_register_dev (struct usb_driver *new_driver, int num_minors, int *start_minor)
+{
+ int i;
+ int j;
+ int good_spot;
+ int retval = -EINVAL;
+
+ dbg ("%s is asking for %d minors", new_driver->name, num_minors);
+
+ if (new_driver->fops == NULL)
+ goto exit;
+
+ *start_minor = 0;
+ spin_lock (&minor_lock);
+ for (i = 0; i < MAX_USB_MINORS; ++i) {
+ if (usb_minors[i])
+ continue;
+
+ good_spot = 1;
+ for (j = 1; j <= num_minors-1; ++j)
+ if (usb_minors[i+j]) {
+ good_spot = 0;
+ break;
+ }
+ if (good_spot == 0)
+ continue;
+
+ *start_minor = i;
+ spin_unlock (&minor_lock);
+ retval = usb_register_minors (new_driver, num_minors, *start_minor);
+ if (retval) {
+ /* someone snuck in here, so let's start looking all over
+again */
+ spin_lock (&minor_lock);
+ i = 0;
+ continue;
+ }
+ goto exit;
+ }
+ spin_unlock (&minor_lock);
+exit:
+ return retval;
+}
+
+/**
+ * usb_deregister_dev - deregister a USB device's dynamic minor.
+ * @driver: USB operations for the driver
+ * @num_minors: number of minor numbers to put back.
+ * @start_minor: the starting minor number
+ *
+ * Used in conjunction with usb_register_dev(). This function is called
+ * when the USB driver is finished with the minor numbers gotten from a
+ * call to usb_register_dev() (usually when the device is disconnected
+ * from the system.)
+ *
+ * This should be called by all drivers that use the USB major number.
+ */
+void usb_deregister_dev (struct usb_driver *driver, int num_minors, int start_minor)
+{
+ usb_deregister_minors (driver, num_minors, start_minor);
+}
+#endif /* CONFIG_USB_DYNAMIC_MINORS */
+
+
/**
* usb_scan_devices - scans all unclaimed USB interfaces
* Context: !in_interrupt ()
@@ -177,12 +300,13 @@
void usb_deregister(struct usb_driver *driver)
{
struct list_head *tmp;
- int i;
info("deregistering driver %s", driver->name);
+
+#ifndef CONFIG_USB_DYNAMIC_MINORS
if (driver->fops != NULL)
- for (i = driver->minor; i < driver->minor + driver->num_minors; ++i)
- usb_minors[i] = NULL;
+ usb_deregister_minors (driver, driver->num_minors, driver->minor);
+#endif
/*
* first we remove the driver, to be sure it doesn't get used by
@@ -2524,14 +2648,14 @@
static int usb_open(struct inode * inode, struct file * file)
{
int minor = minor(inode->i_rdev);
- struct usb_driver *c = usb_minors[minor];
+ struct usb_driver *c;
int err = -ENODEV;
struct file_operations *old_fops, *new_fops = NULL;
- /*
- * No load-on-demand? Randy, could you ACK that it's really not
- * supposed to be done? -- AV
- */
+ spin_lock (&minor_lock);
+ c = usb_minors[minor];
+ spin_unlock (&minor_lock);
+
if (!c || !(new_fops = fops_get(c->fops)))
return err;
old_fops = file->f_op;
@@ -2622,6 +2746,11 @@
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_scan_devices);
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+EXPORT_SYMBOL(usb_register_dev);
+EXPORT_SYMBOL(usb_deregister_dev);
+#endif
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_free_dev);
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h Thu Apr 25 16:26:56 2002
+++ b/include/linux/usb.h Thu Apr 25 16:26:56 2002
@@ -2,6 +2,7 @@
#define __LINUX_USB_H
#include <linux/device.h>
+#include <linux/errno.h>
/* USB constants */
@@ -775,6 +776,14 @@
*/
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
+
+#ifndef CONFIG_USB_DYNAMIC_MINORS
+static inline int usb_register_dev(struct usb_driver *new_driver, int num_minors, int
+*start_minor) { return -ENODEV; }
+static inline void usb_deregister_dev(struct usb_driver *driver, int num_minors, int
+start_minor) {}
+#else
+extern int usb_register_dev(struct usb_driver *new_driver, int num_minors, int
+*start_minor);
+extern void usb_deregister_dev(struct usb_driver *driver, int num_minors, int
+start_minor);
+#endif
/* -------------------------------------------------------------------------- */
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel