summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.help8
-rw-r--r--drivers/usb/class/printer.c21
-rw-r--r--drivers/usb/core/Config.in11
-rw-r--r--drivers/usb/core/usb.c175
-rw-r--r--drivers/usb/host/ehci-hub.c36
-rw-r--r--drivers/usb/host/ohci-hub.c5
-rw-r--r--drivers/usb/image/mdc800.c9
-rw-r--r--drivers/usb/image/scanner.c9
-rw-r--r--drivers/usb/image/scanner.h5
-rw-r--r--drivers/usb/input/hid-core.c2
-rw-r--r--drivers/usb/input/hiddev.c28
-rw-r--r--drivers/usb/media/Makefile2
-rw-r--r--drivers/usb/media/dabusb.c15
-rw-r--r--drivers/usb/media/dabusb.h5
-rw-r--r--drivers/usb/media/usbvideo.c100
-rw-r--r--drivers/usb/media/usbvideo.h29
-rw-r--r--drivers/usb/misc/auerswald.c34
-rw-r--r--drivers/usb/misc/brlvger.c21
-rw-r--r--drivers/usb/net/pegasus.h2
-rw-r--r--drivers/usb/net/usbnet.c33
-rw-r--r--drivers/usb/serial/keyspan.c171
-rw-r--r--drivers/usb/usb-skeleton.c38
22 files changed, 541 insertions, 218 deletions
diff --git a/drivers/usb/Config.help b/drivers/usb/Config.help
index 65b90af25c32..fa161a19725b 100644
--- a/drivers/usb/Config.help
+++ b/drivers/usb/Config.help
@@ -69,3 +69,11 @@ CONFIG_USB_BANDWIDTH
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 --git a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
index abab738e601a..7a589cbd9569 100644
--- a/drivers/usb/class/printer.c
+++ b/drivers/usb/class/printer.c
@@ -107,7 +107,11 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_REQ_RESET 0x02
#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define USBLP_MINORS 256
+#else
#define USBLP_MINORS 16
+#endif
#define USBLP_MINOR_BASE 0
#define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */
@@ -208,6 +212,8 @@ static int usblp_select_alts(struct usblp *usblp);
static int usblp_set_protocol(struct usblp *usblp, int protocol);
static int usblp_cache_device_id_string(struct usblp *usblp);
+/* forward reference to make our lives easier */
+extern struct usb_driver usblp_driver;
/*
* Functions for usblp control messages.
@@ -366,6 +372,7 @@ static void usblp_cleanup (struct usblp *usblp)
{
devfs_unregister (usblp->devfs);
usblp_table [usblp->minor] = NULL;
+ usb_deregister_dev (&usblp_driver, 1, usblp->minor);
info("usblp%d: removed", usblp->minor);
kfree (usblp->writeurb->transfer_buffer);
@@ -801,12 +808,14 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
init_waitqueue_head(&usblp->wait);
usblp->ifnum = ifnum;
- /* Look for a free usblp_table entry. */
- while (usblp_table[usblp->minor]) {
- usblp->minor++;
- if (usblp->minor >= USBLP_MINORS) {
- err("no more free usblp devices");
- goto abort;
+ if (usb_register_dev(&usblp_driver, 1, &usblp->minor)) {
+ /* Look for a free usblp_table entry on our own. */
+ while (usblp_table[usblp->minor]) {
+ usblp->minor++;
+ if (usblp->minor >= USBLP_MINORS) {
+ err("no more free usblp devices");
+ goto abort;
+ }
}
}
diff --git a/drivers/usb/core/Config.in b/drivers/usb/core/Config.in
index 023c2704c026..d1415e679f10 100644
--- a/drivers/usb/core/Config.in
+++ b/drivers/usb/core/Config.in
@@ -4,11 +4,8 @@
bool ' USB verbose debug messages' CONFIG_USB_DEBUG
comment 'Miscellaneous USB options'
-bool ' USB device filesystem' CONFIG_USB_DEVICEFS
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH
-else
- define_bool CONFIG_USB_BANDWIDTH n
-fi
-bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
+ bool ' USB device filesystem' CONFIG_USB_DEVICEFS
+ bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
+dep_bool ' Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH $CONFIG_EXPERIMENTAL
+dep_bool ' Dynamic USB minor allocation (EXPERIMENTAL)' CONFIG_USB_DYNAMIC_MINORS $CONFIG_EXPERIMENTAL
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 7aa2dec50734..0d85e97251e0 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -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 @@ LIST_HEAD(usb_driver_list);
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,20 @@ static struct usb_driver *usb_minors[256];
*/
int usb_register(struct usb_driver *new_driver)
{
- int i;
+ int retval = 0;
+
+ if ((new_driver->fops) && (new_driver->num_minors == 0)) {
+ err ("%s driver must specify num_minors", new_driver->name);
+ return -EINVAL;
+ }
+#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 +139,96 @@ int usb_register(struct usb_driver *new_driver)
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 -ENODEV if CONFIG_USB_DYNAMIC_MINORS is not enabled in this
+ * kernel, -EINVAL if something bad happens with trying to register a
+ * device, 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 +307,13 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
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 +2655,14 @@ int usb_new_device(struct usb_device *dev)
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;
@@ -2623,9 +2754,13 @@ 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);
-EXPORT_SYMBOL(usb_inc_dev_use);
EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
EXPORT_SYMBOL(usb_driver_claim_interface);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 4b2b080663f8..22d4919cbf97 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -91,7 +91,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
- set_bit (i, buf);
+ if (i < 7)
+ buf [0] |= 1 << (i + 1);
+ else
+ buf [1] |= 1 << (i - 7);
status = STS_PCD;
}
}
@@ -141,7 +144,7 @@ static int ehci_hub_control (
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params);
- u32 temp;
+ u32 temp, status;
unsigned long flags;
int retval = 0;
@@ -219,22 +222,22 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- memset (buf, 0, 4);
+ status = 0;
temp = readl (&ehci->regs->port_status [wIndex]);
// wPortChange bits
if (temp & PORT_CSC)
- set_bit (USB_PORT_FEAT_C_CONNECTION, buf);
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
if (temp & PORT_PEC)
- set_bit (USB_PORT_FEAT_C_ENABLE, buf);
+ status |= 1 << USB_PORT_FEAT_C_ENABLE;
// USB_PORT_FEAT_C_SUSPEND
if (temp & PORT_OCC)
- set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf);
+ status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
&& jiffies > ehci->reset_done [wIndex]) {
- set_bit (USB_PORT_FEAT_C_RESET, buf);
+ status |= 1 << USB_PORT_FEAT_C_RESET;
/* force reset to complete */
writel (temp & ~PORT_RESET,
@@ -252,26 +255,27 @@ static int ehci_hub_control (
// don't show wPortStatus if it's owned by a companion hc
if (!(temp & PORT_OWNER)) {
if (temp & PORT_CONNECT) {
- set_bit (USB_PORT_FEAT_CONNECTION, buf);
- set_bit (USB_PORT_FEAT_HIGHSPEED, buf);
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ status |= 1 << USB_PORT_FEAT_HIGHSPEED;
}
if (temp & PORT_PE)
- set_bit (USB_PORT_FEAT_ENABLE, buf);
+ status |= 1 << USB_PORT_FEAT_ENABLE;
if (temp & PORT_SUSPEND)
- set_bit (USB_PORT_FEAT_SUSPEND, buf);
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
if (temp & PORT_OC)
- set_bit (USB_PORT_FEAT_OVER_CURRENT, buf);
+ status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
if (temp & PORT_RESET)
- set_bit (USB_PORT_FEAT_RESET, buf);
+ status |= 1 << USB_PORT_FEAT_RESET;
if (temp & PORT_POWER)
- set_bit (USB_PORT_FEAT_POWER, buf);
+ status |= 1 << USB_PORT_FEAT_POWER;
}
#ifndef EHCI_VERBOSE_DEBUG
- if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
+ if (status & ~0xffff) /* only if wPortChange is interesting */
#endif
dbg_port (hcd, "GetStatus", wIndex + 1, temp);
- cpu_to_le32s ((u32 *) buf);
+ // we "know" this alignment is good, caller used kmalloc()...
+ *((u32 *) buf) = cpu_to_le32 (status);
break;
case SetHubFeature:
switch (wValue) {
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 2aed53548bb5..faa9acf49ea6 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -96,7 +96,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
| RH_PS_OCIC | RH_PS_PRSC;
if (status) {
changed = 1;
- set_bit (i + 1, buf);
+ if (i < 7)
+ buf [0] |= 1 << (i + 1);
+ else
+ buf [1] |= 1 << (i - 7);
}
}
return changed ? length : 0;
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 58d55e3e1d66..c211b9980c80 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -119,8 +119,12 @@
#define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND
#define TO_GET_READY TO_DEFAULT_COMMAND
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define MDC800_DEVICE_MINOR_BASE 0
+#else
/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
#define MDC800_DEVICE_MINOR_BASE 32
+#endif
/**************************************************************************
@@ -176,6 +180,7 @@ struct mdc800_data
int pic_index; // Cache for the Imagesize (-1 for nothing cached )
int pic_len;
+ int minor;
};
@@ -470,6 +475,8 @@ static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum,
down (&mdc800->io_lock);
+ usb_register_dev (&mdc800_usb_driver, 1, &mdc800->minor);
+
mdc800->dev=dev;
mdc800->open=0;
@@ -525,6 +532,8 @@ static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
if (mdc800->state == NOT_CONNECTED)
return;
+ usb_deregister_dev (&mdc800_usb_driver, 1, mdc800->minor);
+
mdc800->state=NOT_CONNECTED;
usb_unlink_urb (mdc800->irq_urb);
diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
index d66b8e6eb865..d26c0d17635e 100644
--- a/drivers/usb/image/scanner.c
+++ b/drivers/usb/image/scanner.c
@@ -953,9 +953,11 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
down(&scn_mutex);
- for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
- if (!p_scn_table[scn_minor])
- break;
+ if (usb_register_dev(&scanner_driver, 1, &scn_minor)) {
+ for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
+ if (!p_scn_table[scn_minor])
+ break;
+ }
}
/* Check to make sure that the last slot isn't already taken */
@@ -1086,6 +1088,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
devfs_unregister(scn->devfs);
+ usb_deregister_dev(&scanner_driver, 1, scn->scn_minor);
p_scn_table[scn->scn_minor] = NULL;
usb_free_urb(scn->scn_irq);
up (&(scn->sem));
diff --git a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
index be6c26ac1f9c..7e07b5f84469 100644
--- a/drivers/usb/image/scanner.h
+++ b/drivers/usb/image/scanner.h
@@ -233,8 +233,13 @@ MODULE_DEVICE_TABLE (usb, scanner_device_ids);
#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest)
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define SCN_MAX_MNR 256
+#define SCN_BASE_MNR 0
+#else
#define SCN_MAX_MNR 16 /* We're allocated 16 minors */
#define SCN_BASE_MNR 48 /* USB Scanners start at minor 48 */
+#endif
static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 245ad1a0b5af..e47a8d53e781 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1271,6 +1271,7 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
#define USB_DEVICE_ID_ATEN_CS124U 0x2202
#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
struct hid_blacklist {
__u16 idVendor;
@@ -1288,6 +1289,7 @@ struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ 0, 0 }
};
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 05b02b4c93fa..271ee088571e 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -25,10 +25,7 @@
* e-mail - mail your message to Paul Stewart <stewart@wetlogic.net>
*/
-#define HIDDEV_MINOR_BASE 96
-#define HIDDEV_MINORS 16
-#define HIDDEV_BUFFER_SIZE 64
-
+#include <linux/config.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -39,6 +36,15 @@
#include "hid.h"
#include <linux/hiddev.h>
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define HIDDEV_MINOR_BASE 0
+#define HIDDEV_MINORS 256
+#else
+#define HIDDEV_MINOR_BASE 96
+#define HIDDEV_MINORS 16
+#endif
+#define HIDDEV_BUFFER_SIZE 64
+
struct hiddev {
int exist;
int open;
@@ -62,6 +68,9 @@ struct hiddev_list {
static struct hiddev *hiddev_table[HIDDEV_MINORS];
static devfs_handle_t hiddev_devfs_handle;
+/* forward reference to make our lives easier */
+extern struct usb_driver hiddev_driver;
+
/*
* Find a report, given the report's type and ID. The ID can be specified
* indirectly by REPORT_ID_FIRST (which returns the first report of the given
@@ -184,6 +193,7 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static void hiddev_cleanup(struct hiddev *hiddev)
{
devfs_unregister(hiddev->devfs);
+ usb_deregister_dev(&hiddev_driver, 1, hiddev->minor);
hiddev_table[hiddev->minor] = NULL;
kfree(hiddev);
}
@@ -605,10 +615,12 @@ int hiddev_connect(struct hid_device *hid)
if (i == hid->maxapplication)
return -1;
- for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++);
- if (minor == HIDDEV_MINORS) {
- printk(KERN_ERR "hiddev: no more free hiddev devices\n");
- return -1;
+ if (usb_register_dev (&hiddev_driver, 1, &minor)) {
+ for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++);
+ if (minor == HIDDEV_MINORS) {
+ printk(KERN_ERR "hiddev: no more free hiddev devices\n");
+ return -1;
+ }
}
if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
index 7b1d43f40130..1eb02f0872a4 100644
--- a/drivers/usb/media/Makefile
+++ b/drivers/usb/media/Makefile
@@ -4,7 +4,7 @@
O_TARGET := media.o
-export-objs := ov511.o pwc-uncompress.o
+export-objs := ov511.o pwc-uncompress.o usbvideo.o
pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
index 50d75410bbcd..30dfc3930cc6 100644
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -52,12 +52,17 @@
/* --------------------------------------------------------------------- */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define NRDABUSB 256
+#else
#define NRDABUSB 4
+#endif
/*-------------------------------------------------------------------*/
static dabusb_t dabusb[NRDABUSB];
static int buffers = 256;
+extern struct usb_driver dabusb_driver;
/*-------------------------------------------------------------------*/
@@ -734,15 +739,18 @@ static void *dabusb_probe (struct usb_device *usbdev, unsigned int ifnum,
if (ifnum != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
return NULL;
- devnum = dabusb_find_struct ();
- if (devnum == -1)
- return NULL;
+ if (usb_register_dev (&dabusb_driver, 1, &devnum)) {
+ devnum = dabusb_find_struct ();
+ if (devnum == -1)
+ return NULL;
+ }
s = &dabusb[devnum];
down (&s->mutex);
s->remove_pending = 0;
s->usbdev = usbdev;
+ s->devnum = devnum;
if (usb_set_configuration (usbdev, usbdev->config[0].bConfigurationValue) < 0) {
err("set_configuration failed");
@@ -777,6 +785,7 @@ static void dabusb_disconnect (struct usb_device *usbdev, void *ptr)
dbg("dabusb_disconnect");
+ usb_deregister_dev (&dabusb_driver, 1, s->devnum);
s->remove_pending = 1;
wake_up (&s->wait);
if (s->state == _started)
diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h
index 9fc09c8a289f..259001584a7f 100644
--- a/drivers/usb/media/dabusb.h
+++ b/drivers/usb/media/dabusb.h
@@ -6,7 +6,11 @@ typedef struct
unsigned int pipe;
}bulk_transfer_t,*pbulk_transfer_t;
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define DABUSB_MINOR 0
+#else
#define DABUSB_MINOR 240 /* some unassigned USB minor */
+#endif
#define DABUSB_VERSION 0x1000
#define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t)
#define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int)
@@ -31,6 +35,7 @@ typedef struct
unsigned int overruns;
int readptr;
int opened;
+ int devnum;
struct list_head free_buff_list;
struct list_head rec_buff_list;
} dabusb_t,*pdabusb_t;
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
index c04a67e6c45c..60cf00f71c19 100644
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -18,7 +18,6 @@
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/slab.h>
-#define __NO_VERSION__ /* Temporary: usbvideo is not a module yet */
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
@@ -55,6 +54,24 @@ static int usbvideo_default_procfs_write_proc(
unsigned long count, void *data);
#endif
+static void usbvideo_Disconnect(struct usb_device *dev, void *ptr);
+static void usbvideo_CameraRelease(uvd_t *uvd);
+
+static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
+static int usbvideo_v4l_open(struct inode *inode, struct file *file);
+static int usbvideo_v4l_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos);
+static int usbvideo_v4l_close(struct inode *inode, struct file *file);
+
+static int usbvideo_StartDataPump(uvd_t *uvd);
+static void usbvideo_StopDataPump(uvd_t *uvd);
+static int usbvideo_GetFrame(uvd_t *uvd, int frameNum);
+static int usbvideo_NewFrame(uvd_t *uvd, int framenum);
+static void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd,
+ usbvideo_frame_t *frame);
+
/*******************************/
/* Memory management functions */
/*******************************/
@@ -73,7 +90,7 @@ unsigned long usbvideo_kvirt_to_pa(unsigned long adr)
return ret;
}
-void *usbvideo_rvmalloc(unsigned long size)
+static void *usbvideo_rvmalloc(unsigned long size)
{
void *mem;
unsigned long adr;
@@ -94,7 +111,7 @@ void *usbvideo_rvmalloc(unsigned long size)
return mem;
}
-void usbvideo_rvfree(void *mem, unsigned long size)
+static void usbvideo_rvfree(void *mem, unsigned long size)
{
unsigned long adr;
@@ -110,13 +127,13 @@ void usbvideo_rvfree(void *mem, unsigned long size)
vfree(mem);
}
-void RingQueue_Initialize(RingQueue_t *rq)
+static void RingQueue_Initialize(RingQueue_t *rq)
{
assert(rq != NULL);
init_waitqueue_head(&rq->wqh);
}
-void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
+static void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
{
assert(rq != NULL);
assert(rqLen > 0);
@@ -125,14 +142,14 @@ void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
assert(rq->queue != NULL);
}
-int RingQueue_IsAllocated(const RingQueue_t *rq)
+static int RingQueue_IsAllocated(const RingQueue_t *rq)
{
if (rq == NULL)
return 0;
return (rq->queue != NULL) && (rq->length > 0);
}
-void RingQueue_Free(RingQueue_t *rq)
+static void RingQueue_Free(RingQueue_t *rq)
{
assert(rq != NULL);
if (RingQueue_IsAllocated(rq)) {
@@ -154,6 +171,8 @@ int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len)
return len;
}
+EXPORT_SYMBOL(RingQueue_Dequeue);
+
int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n)
{
int enqueued = 0;
@@ -184,6 +203,8 @@ int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n)
return enqueued;
}
+EXPORT_SYMBOL(RingQueue_Enqueue);
+
int RingQueue_GetLength(const RingQueue_t *rq)
{
int ri, wi;
@@ -200,7 +221,9 @@ int RingQueue_GetLength(const RingQueue_t *rq)
return wi + (rq->length - ri);
}
-void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
+EXPORT_SYMBOL(RingQueue_GetLength);
+
+static void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
{
assert(rq != NULL);
interruptible_sleep_on(&rq->wqh);
@@ -213,6 +236,8 @@ void RingQueue_WakeUpInterruptible(RingQueue_t *rq)
wake_up_interruptible(&rq->wqh);
}
+EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
+
/*
* usbvideo_VideosizeToString()
*
@@ -222,7 +247,7 @@ void RingQueue_WakeUpInterruptible(RingQueue_t *rq)
* 07-Aug-2000 Created.
* 19-Oct-2000 Reworked for usbvideo module.
*/
-void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
+static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
{
char tmp[40];
int n;
@@ -241,8 +266,8 @@ void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
* History:
* 01-Feb-2000 Created.
*/
-void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
- int x, int y, int ch)
+static void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
+ int x, int y, int ch)
{
static const unsigned short digits[16] = {
0xF6DE, /* 0 */
@@ -296,8 +321,8 @@ void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
* History:
* 01-Feb-2000 Created.
*/
-void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
- int x, int y, const char *str)
+static void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
+ int x, int y, const char *str)
{
while (*str) {
usbvideo_OverlayChar(uvd, frame, x, y, *str);
@@ -314,7 +339,7 @@ void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
* History:
* 01-Feb-2000 Created.
*/
-void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
+static void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
{
const int y_diff = 8;
char tmp[16];
@@ -437,7 +462,7 @@ void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
* History:
* 14-Jan-2000 Corrected default multiplier.
*/
-void usbvideo_ReportStatistics(const uvd_t *uvd)
+static void usbvideo_ReportStatistics(const uvd_t *uvd)
{
if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
unsigned long allPackets, badPackets, goodPackets, percent;
@@ -549,6 +574,8 @@ void usbvideo_DrawLine(
}
}
+EXPORT_SYMBOL(usbvideo_DrawLine);
+
/*
* usbvideo_TestPattern()
*
@@ -636,6 +663,8 @@ void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode)
usbvideo_OverlayStats(uvd, frame);
}
+EXPORT_SYMBOL(usbvideo_TestPattern);
+
/*
* usbvideo_HexDump()
*
@@ -663,6 +692,8 @@ void usbvideo_HexDump(const unsigned char *data, int len)
printk("%s\n", tmp);
}
+EXPORT_SYMBOL(usbvideo_HexDump);
+
/* Debugging aid */
void usbvideo_SayAndWait(const char *what)
{
@@ -672,6 +703,8 @@ void usbvideo_SayAndWait(const char *what)
interruptible_sleep_on_timeout (&wq, HZ*3); /* Timeout */
}
+EXPORT_SYMBOL(usbvideo_SayAndWait);
+
/* ******************************************************************** */
static void usbvideo_ClientIncModCount(uvd_t *uvd)
@@ -825,6 +858,8 @@ int usbvideo_register(
return 0;
}
+EXPORT_SYMBOL(usbvideo_register);
+
/*
* usbvideo_Deregister()
*
@@ -886,6 +921,8 @@ void usbvideo_Deregister(usbvideo_t **pCams)
*pCams = NULL;
}
+EXPORT_SYMBOL(usbvideo_Deregister);
+
/*
* usbvideo_Disconnect()
*
@@ -908,7 +945,7 @@ void usbvideo_Deregister(usbvideo_t **pCams)
* 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
* 19-Oct-2000 Moved to usbvideo module.
*/
-void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
+static void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
{
static const char proc[] = "usbvideo_Disconnect";
uvd_t *uvd = (uvd_t *) ptr;
@@ -958,7 +995,7 @@ void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
* History:
* 27-Jan-2000 Created.
*/
-void usbvideo_CameraRelease(uvd_t *uvd)
+static void usbvideo_CameraRelease(uvd_t *uvd)
{
static const char proc[] = "usbvideo_CameraRelease";
if (uvd == NULL) {
@@ -1079,6 +1116,8 @@ allocate_done:
return uvd;
}
+EXPORT_SYMBOL(usbvideo_AllocateDevice);
+
int usbvideo_RegisterVideoDevice(uvd_t *uvd)
{
static const char proc[] = "usbvideo_RegisterVideoDevice";
@@ -1139,9 +1178,11 @@ int usbvideo_RegisterVideoDevice(uvd_t *uvd)
return 0;
}
+EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
+
/* ******************************************************************** */
-int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
+static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
{
uvd_t *uvd = file->private_data;
unsigned long start = vma->vm_start;
@@ -1185,7 +1226,7 @@ int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
* 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
* 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
*/
-int usbvideo_v4l_open(struct inode *inode, struct file *file)
+static int usbvideo_v4l_open(struct inode *inode, struct file *file)
{
static const char proc[] = "usbvideo_v4l_open";
struct video_device *dev = video_devdata(file);
@@ -1300,7 +1341,7 @@ int usbvideo_v4l_open(struct inode *inode, struct file *file)
* 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
* 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
*/
-int usbvideo_v4l_close(struct inode *inode, struct file *file)
+static int usbvideo_v4l_close(struct inode *inode, struct file *file)
{
static const char proc[] = "usbvideo_v4l_close";
struct video_device *dev = file->private_data;
@@ -1554,7 +1595,7 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
-int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
@@ -1571,7 +1612,7 @@ int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
* 20-Oct-2000 Created.
* 01-Nov-2000 Added mutex (uvd->lock).
*/
-int usbvideo_v4l_read(struct file *file, char *buf,
+static int usbvideo_v4l_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
static const char proc[] = "usbvideo_v4l_read";
@@ -1809,7 +1850,7 @@ urb_done_with:
* of hardcoded values. Simplified by using for loop,
* allowed any number of URBs.
*/
-int usbvideo_StartDataPump(uvd_t *uvd)
+static int usbvideo_StartDataPump(uvd_t *uvd)
{
static const char proc[] = "usbvideo_StartDataPump";
struct usb_device *dev = uvd->dev;
@@ -1885,7 +1926,7 @@ int usbvideo_StartDataPump(uvd_t *uvd)
* 22-Jan-2000 Corrected order of actions to work after surprise removal.
* 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
*/
-void usbvideo_StopDataPump(uvd_t *uvd)
+static void usbvideo_StopDataPump(uvd_t *uvd)
{
static const char proc[] = "usbvideo_StopDataPump";
int i, j;
@@ -1929,7 +1970,7 @@ void usbvideo_StopDataPump(uvd_t *uvd)
* 29-Mar-00 Added copying of previous frame into the current one.
* 6-Aug-00 Added model 3 video sizes, removed redundant width, height.
*/
-int usbvideo_NewFrame(uvd_t *uvd, int framenum)
+static int usbvideo_NewFrame(uvd_t *uvd, int framenum)
{
usbvideo_frame_t *frame;
int n;
@@ -2004,7 +2045,7 @@ int usbvideo_NewFrame(uvd_t *uvd, int framenum)
* FLAGS_NO_DECODING set. Therefore, any regular build of any driver
* based on usbvideo can use this feature at any time.
*/
-void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
+static void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
{
int n;
@@ -2034,7 +2075,7 @@ void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
}
}
-int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
+static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
{
static const char proc[] = "usbvideo_GetFrame";
usbvideo_frame_t *frame = &uvd->frame[frameNum];
@@ -2225,6 +2266,8 @@ void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame)
usbvideo_OverlayStats(uvd, frame);
}
+EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
+
/*
* usbvideo_SoftwareContrastAdjustment()
*
@@ -2235,7 +2278,8 @@ void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame)
* History:
* 09-Feb-2001 Created.
*/
-void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, usbvideo_frame_t *frame)
+static void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd,
+ usbvideo_frame_t *frame)
{
static const char proc[] = "usbvideo_SoftwareContrastAdjustment";
int i, j, v4l_linesize;
diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
index 211249c340db..507d56984de8 100644
--- a/drivers/usb/media/usbvideo.h
+++ b/drivers/usb/media/usbvideo.h
@@ -304,35 +304,22 @@ typedef struct s_usbvideo_t usbvideo_t;
#define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
-void RingQueue_Initialize(RingQueue_t *rq);
-void RingQueue_Allocate(RingQueue_t *rq, int rqLen);
-int RingQueue_IsAllocated(const RingQueue_t *rq);
-void RingQueue_Free(RingQueue_t *rq);
int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len);
int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n);
int RingQueue_GetLength(const RingQueue_t *rq);
-void RingQueue_InterruptibleSleepOn(RingQueue_t *rq);
void RingQueue_WakeUpInterruptible(RingQueue_t *rq);
-void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame);
void usbvideo_DrawLine(
usbvideo_frame_t *frame,
int x1, int y1,
int x2, int y2,
unsigned char cr, unsigned char cg, unsigned char cb);
void usbvideo_HexDump(const unsigned char *data, int len);
-void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame, int x, int y, int ch);
-void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame, int x, int y, const char *str);
-void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame);
-void usbvideo_ReportStatistics(const uvd_t *uvd);
void usbvideo_SayAndWait(const char *what);
void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode);
-void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs);
/* Memory allocation routines */
unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
-void *usbvideo_rvmalloc(unsigned long size);
-void usbvideo_rvfree(void *mem, unsigned long size);
int usbvideo_register(
usbvideo_t **pCams,
@@ -344,24 +331,10 @@ int usbvideo_register(
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams);
int usbvideo_RegisterVideoDevice(uvd_t *uvd);
void usbvideo_Deregister(usbvideo_t **uvt);
-void usbvideo_Disconnect(struct usb_device *dev, void *ptr);
-void usbvideo_CameraRelease(uvd_t *uvd);
-int usbvideo_v4l_close(struct inode *inode, struct file *file);
int usbvideo_v4l_initialize(struct video_device *dev);
-int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
-int usbvideo_v4l_open(struct inode *inode, struct file *file);
-int usbvideo_v4l_read(struct file *file, char *buf,
- size_t count, loff_t *ppos);
-
-int usbvideo_GetFrame(uvd_t *uvd, int frameNum);
-int usbvideo_NewFrame(uvd_t *uvd, int framenum);
-int usbvideo_StartDataPump(uvd_t *uvd);
-void usbvideo_StopDataPump(uvd_t *uvd);
+
void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame);
-void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, usbvideo_frame_t *frame);
/*
* This code performs bounds checking - use it when working with
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 3c435f78ef4b..579f6ab2f9ef 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -60,12 +60,17 @@ do { \
/* Auerswald Vendor ID */
#define ID_AUERSWALD 0x09BF
-#ifndef AUER_MINOR_BASE /* allow external override */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+/* we can have up to 256 devices at once */
+#define AUER_MINOR_BASE 0
+#define AUER_MAX_DEVICES 256
+#else
#define AUER_MINOR_BASE 112 /* auerswald driver minor number */
-#endif
/* we can have up to this number of device plugged in at once */
#define AUER_MAX_DEVICES 16
+#endif
+
/* prefix for the device descriptors in /dev/usb */
#define AU_PREFIX "auer"
@@ -284,6 +289,7 @@ typedef struct
/* Forwards */
static void auerswald_ctrlread_complete (struct urb * urb);
static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
+extern struct usb_driver auerswald_driver;
/*-------------------------------------------------------------------*/
@@ -1941,16 +1947,18 @@ static void *auerswald_probe (struct usb_device *usbdev, unsigned int ifnum,
auerbuf_init (&cp->bufctl);
init_waitqueue_head (&cp->bufferwait);
- /* find a free slot in the device table */
down (&dev_table_mutex);
- for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
- if (dev_table[dtindex] == NULL)
- break;
- }
- if ( dtindex >= AUER_MAX_DEVICES) {
- err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
- up (&dev_table_mutex);
- goto pfail;
+ if (usb_register_dev (&auerswald_driver, 1, &dtindex)) {
+ /* find a free slot in the device table */
+ for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
+ if (dev_table[dtindex] == NULL)
+ break;
+ }
+ if ( dtindex >= AUER_MAX_DEVICES) {
+ err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
+ up (&dev_table_mutex);
+ goto pfail;
+ }
}
/* Give the device a name */
@@ -2081,6 +2089,9 @@ static void auerswald_disconnect (struct usb_device *usbdev, void *driver_contex
/* Nobody can see this device any more */
devfs_unregister (cp->devfs);
+ /* give back our USB minor number */
+ usb_deregister_dev (&auerswald_driver, 1, cp->dtindex);
+
/* Stop the interrupt endpoint */
auerswald_int_release (cp);
@@ -2181,6 +2192,7 @@ static void __exit auerswald_cleanup (void)
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
module_init (auerswald_init);
module_exit (auerswald_cleanup);
diff --git a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
index a9d458b438ea..e77d0a1e466a 100644
--- a/drivers/usb/misc/brlvger.c
+++ b/drivers/usb/misc/brlvger.c
@@ -315,14 +315,16 @@ brlvger_probe (struct usb_device *dev, unsigned ifnum,
down(&reserve_sem);
- for( i = 0; i < MAX_NR_BRLVGER_DEVS; i++ )
- if( display_table[i] == NULL )
- break;
-
- if( i == MAX_NR_BRLVGER_DEVS ) {
- err( "This driver cannot handle more than %d "
- "braille displays", MAX_NR_BRLVGER_DEVS);
- goto error;
+ if (usb_register_dev(&brlvger_driver, 1, &i)) {
+ for( i = 0; i < MAX_NR_BRLVGER_DEVS; i++ )
+ if( display_table[i] == NULL )
+ break;
+
+ if( i == MAX_NR_BRLVGER_DEVS ) {
+ err( "This driver cannot handle more than %d "
+ "braille displays", MAX_NR_BRLVGER_DEVS);
+ goto error;
+ }
}
if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){
@@ -423,7 +425,8 @@ brlvger_disconnect(struct usb_device *dev, void *ptr)
info("Display %d disconnecting", priv->subminor);
devfs_unregister(priv->devfs);
-
+ usb_deregister_dev(&brlvger_driver, 1, priv->subminor);
+
down(&disconnect_sem);
display_table[priv->subminor] = NULL;
up(&disconnect_sem);
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index a7f0cb56be54..1004eaeb756a 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -255,6 +255,8 @@ PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
DEFAULT_GPIO_RESET )
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index c329ed692ce5..4886279ba1e6 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -121,7 +121,7 @@
#define CONFIG_USB_PL2301
-#define DRIVER_VERSION "06-Apr-2002"
+#define DRIVER_VERSION "26-Apr-2002"
/*-------------------------------------------------------------------------*/
@@ -484,14 +484,6 @@ static int genelink_free (struct usbnet *dev)
return 0;
}
-#else
-
-static int genelink_check_connect (struct usbnet *dev)
-{
- dbg ("%s: assuming peer is connected", dev->net.name);
- return 0;
-}
-
#endif
// reset the device status
@@ -623,12 +615,15 @@ static const struct driver_info genelink_info = {
description: "Genesys GeneLink",
flags: FLAG_FRAMING_GL | FLAG_NO_SETINT,
reset: genelink_reset,
- check_connect: genelink_check_connect,
rx_fixup: genelink_rx_fixup,
tx_fixup: genelink_tx_fixup,
in: 1, out: 2,
epsize: 64,
+
+#ifdef GENELINK_ACK
+ check_connect: genelink_check_connect,
+#endif
};
#endif /* CONFIG_USB_GENESYS */
@@ -652,11 +647,15 @@ static const struct driver_info genelink_info = {
*
*-------------------------------------------------------------------------*/
+static int linuxdev_check_connect (struct usbnet *dev)
+{
+ return 0; // by definition, always connected
+}
static const struct driver_info linuxdev_info = {
description: "Linux Device",
// no reset defined (yet?)
- // no check_connect needed!
+ check_connect: linuxdev_check_connect,
in: 2, out: 1,
epsize: 64,
};
@@ -1169,21 +1168,11 @@ static int pl_reset (struct usbnet *dev)
PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
}
-static int pl_check_connect (struct usbnet *dev)
-{
- // FIXME test interrupt data PL_PEER_E bit
- // plus, there's some handshake done by
- // the prolific win32 driver...
- dbg ("%s: assuming peer is connected", dev->net.name);
- return 0;
-}
-
static const struct driver_info prolific_info = {
description: "Prolific PL-2301/PL-2302",
flags: FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */
reset: pl_reset,
- check_connect: pl_check_connect,
in: 3, out: 2,
epsize: 64,
@@ -1567,7 +1556,7 @@ static int usbnet_ethtool_ioctl (struct net_device *net, void *useraddr)
if (dev->driver_info->check_connect) {
struct ethtool_value edata = { ETHTOOL_GLINK };
- edata.data = dev->driver_info->check_connect (dev);
+ edata.data = dev->driver_info->check_connect (dev) == 0;
if (copy_to_user (useraddr, &edata, sizeof (edata)))
return -EFAULT;
return 0;
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 254c25c99797..03183dcb48bd 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -28,6 +28,14 @@
Change History
+ Wed Apr 25 12:00:00 PST 2002 (Keyspan)
+ Started with Hugh Blemings' code dated Jan 17, 2002. All adapters
+ now supported (including QI and QW). Modified port open, port
+ close, and send setup() logic to fix various data and endpoint
+ synchronization bugs and device LED status bugs. Changed keyspan_
+ write_room() to accurately return transmit buffer availability.
+ Changed forwardingLength from 1 to 16 for all adapters.
+
Fri Oct 12 16:45:00 EST 2001
Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
@@ -98,7 +106,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.1.2"
+#define DRIVER_VERSION "v1.1.3"
#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
@@ -423,9 +431,10 @@ static void usa26_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
- }
+ if (port->open_count)
+ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ }
return;
}
@@ -461,7 +470,7 @@ static void usa26_outcont_callback(struct urb *urb)
if (p_priv->resend_cont) {
dbg ("%s - sending setup", __FUNCTION__);
- keyspan_usa26_send_setup(port->serial, port, 0);
+ keyspan_usa26_send_setup(port->serial, port, p_priv->resend_cont - 1);
}
}
@@ -519,12 +528,12 @@ static void usa26_instat_callback(struct urb *urb)
/* wake_up_interruptible(&p_priv->open_wait); */
}
-exit:
/* Resubmit urb so we continue receiving */
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
}
+exit:
}
static void usa26_glocont_callback(struct urb *urb)
@@ -572,9 +581,10 @@ static void usa28_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
- }
+ if (port->open_count)
+ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ }
p_priv->in_flip ^= 1;
urb = p_priv->in_urbs[p_priv->in_flip];
@@ -596,7 +606,7 @@ static void usa28_outcont_callback(struct urb *urb)
if (p_priv->resend_cont) {
dbg ("%s - sending setup", __FUNCTION__);
- keyspan_usa28_send_setup(port->serial, port, 0);
+ keyspan_usa28_send_setup(port->serial, port, p_priv->resend_cont - 1);
}
}
@@ -653,12 +663,12 @@ static void usa28_instat_callback(struct urb *urb)
/* wake_up_interruptible(&p_priv->open_wait); */
}
-exit:
/* Resubmit urb so we continue receiving */
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
}
+exit:
}
static void usa28_glocont_callback(struct urb *urb)
@@ -683,7 +693,7 @@ static void usa49_glocont_callback(struct urb *urb)
if (p_priv->resend_cont) {
dbg ("%s - sending setup", __FUNCTION__);
- keyspan_usa49_send_setup(serial, port, 0);
+ keyspan_usa49_send_setup(serial, port, p_priv->resend_cont - 1);
break;
}
}
@@ -745,13 +755,13 @@ static void usa49_instat_callback(struct urb *urb)
/* wake_up_interruptible(&p_priv->open_wait); */
}
-exit:
/* Resubmit urb so we continue receiving */
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
}
+exit:
}
static void usa49_inack_callback(struct urb *urb)
@@ -805,9 +815,10 @@ static void usa49_indat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
- if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
- }
+ if (port->open_count)
+ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ }
}
/* not used, usa-49 doesn't have per-port control endpoints */
@@ -820,9 +831,27 @@ static void usa49_outcont_callback(struct urb *urb)
static int keyspan_write_room (struct usb_serial_port *port)
{
+ struct keyspan_port_private *p_priv;
+ const struct keyspan_device_details *d_details;
+ int flip;
+ struct urb *this_urb;
+
dbg("%s", __FUNCTION__);
- return (32);
+ p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = p_priv->device_details;
+ flip = p_priv->out_flip;
+
+ /* Check both endpoints to see if any are available. */
+ if ((this_urb = p_priv->out_urbs[flip]) != 0) {
+ if (this_urb->status != -EINPROGRESS)
+ return (63);
+ flip = (flip + 1) & d_details->outdat_endp_flip;
+ if ((this_urb = p_priv->out_urbs[flip]) != 0)
+ if (this_urb->status != -EINPROGRESS)
+ return (63);
+ }
+ return (0);
}
@@ -873,7 +902,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
if ((urb = p_priv->out_urbs[i]) == NULL)
continue;
urb->dev = serial->dev;
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0);
+ /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
}
keyspan_send_setup(port, 1);
@@ -909,8 +938,12 @@ static void keyspan_close(struct usb_serial_port *port, struct file *filp)
p_priv->rts_state = 0;
p_priv->dtr_state = 0;
- if (serial->dev)
- keyspan_send_setup(port, 1);
+ if (serial->dev) {
+ keyspan_send_setup(port, 2);
+ /* pilot-xfer seems to work best with this delay */
+ mdelay(100);
+ keyspan_set_termios(port, NULL);
+ }
/*while (p_priv->outcont_urb->status == -EINPROGRESS) {
dbg("%s - urb in progress", __FUNCTION__);
@@ -922,7 +955,7 @@ static void keyspan_close(struct usb_serial_port *port, struct file *filp)
if (serial->dev) {
/* Stop reading/writing urbs */
stop_urb(p_priv->inack_urb);
- stop_urb(p_priv->outcont_urb);
+ /* stop_urb(p_priv->outcont_urb); */
for (i = 0; i < 2; i++) {
stop_urb(p_priv->in_urbs[i]);
stop_urb(p_priv->out_urbs[i]);
@@ -1365,7 +1398,10 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
return -1;
}
- p_priv->resend_cont = 1;
+ /* Save reset port val for resend.
+ Don't overwrite resend for close condition. */
+ if (p_priv->resend_cont != 3)
+ p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
/* dbg ("%s - already writing", __FUNCTION__); */
return(-1);
@@ -1414,12 +1450,26 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
msg.xonFlowControl = 0;
msg.setFlowControl = 0xff;
-
- msg.forwardingLength = 1;
+ msg.forwardingLength = 16;
msg.xonChar = 17;
msg.xoffChar = 19;
- if (reset_port) {
+ /* Opening port */
+ if (reset_port == 1) {
+ msg._txOn = 1;
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 1;
+ msg.rxOff = 0;
+ msg.rxFlush = 1;
+ msg.rxForward = 0;
+ msg.returnStatus = 0;
+ msg.resetDataToggle = 0xff;
+ }
+
+ /* Closing port */
+ else if (reset_port == 2) {
msg._txOn = 0;
msg._txOff = 1;
msg.txFlush = 0;
@@ -1429,14 +1479,16 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
msg.rxFlush = 1;
msg.rxForward = 0;
msg.returnStatus = 0;
- msg.resetDataToggle = 0xff;
+ msg.resetDataToggle = 0;
}
+
+ /* Sending intermediate configs */
else {
msg._txOn = (! p_priv->break_on);
msg._txOff = 0;
msg.txFlush = 0;
msg.txBreak = (p_priv->break_on);
- msg.rxOn = 1;
+ msg.rxOn = 0;
msg.rxOff = 0;
msg.rxFlush = 0;
msg.rxForward = 0;
@@ -1496,7 +1548,10 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
return -1;
}
- p_priv->resend_cont = 1;
+ /* Save reset port val for resend.
+ Don't overwrite resend for close condition. */
+ if (p_priv->resend_cont != 3)
+ p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
dbg ("%s already writing", __FUNCTION__);
return(-1);
@@ -1522,7 +1577,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
msg.rts = p_priv->rts_state;
msg.dtr = p_priv->dtr_state;
- msg.forwardingLength = 1;
+ msg.forwardingLength = 16;
msg.forwardMs = 10;
msg.breakThreshold = 45;
msg.xonChar = 17;
@@ -1530,8 +1585,22 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
/*msg.returnStatus = 1;
msg.resetDataToggle = 0xff;*/
-
- if (reset_port) {
+ /* Opening port */
+ if (reset_port == 1) {
+ msg._txOn = 1;
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txForceXoff = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 1;
+ msg.rxOff = 0;
+ msg.rxFlush = 1;
+ msg.rxForward = 0;
+ msg.returnStatus = 0;
+ msg.resetDataToggle = 0xff;
+ }
+ /* Closing port */
+ else if (reset_port == 2) {
msg._txOn = 0;
msg._txOff = 1;
msg.txFlush = 0;
@@ -1542,15 +1611,16 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
msg.rxFlush = 1;
msg.rxForward = 0;
msg.returnStatus = 0;
- msg.resetDataToggle = 0xff;
+ msg.resetDataToggle = 0;
}
+ /* Sending intermediate configs */
else {
msg._txOn = (! p_priv->break_on);
msg._txOff = 0;
msg.txFlush = 0;
msg.txForceXoff = 0;
msg.txBreak = (p_priv->break_on);
- msg.rxOn = 1;
+ msg.rxOn = 0;
msg.rxOff = 0;
msg.rxFlush = 0;
msg.rxForward = 0;
@@ -1610,7 +1680,10 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
return -1;
}
- p_priv->resend_cont = 1;
+ /* Save reset port val for resend.
+ Don't overwrite resend for close condition. */
+ if (p_priv->resend_cont != 3)
+ p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
/* dbg ("%s - already writing", __FUNCTION__); */
return(-1);
@@ -1663,11 +1736,27 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
msg.xonFlowControl = 0;
msg.setFlowControl = 0xff;
- msg.forwardingLength = 1;
+ msg.forwardingLength = 16;
msg.xonChar = 17;
msg.xoffChar = 19;
- if (reset_port) {
+ /* Opening port */
+ if (reset_port == 1) {
+ msg._txOn = 1;
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 1;
+ msg.rxOff = 0;
+ msg.rxFlush = 1;
+ msg.rxForward = 0;
+ msg.returnStatus = 0;
+ msg.resetDataToggle = 0xff;
+ msg.enablePort = 1;
+ msg.disablePort = 0;
+ }
+ /* Closing port */
+ else if (reset_port == 2) {
msg._txOn = 0;
msg._txOff = 1;
msg.txFlush = 0;
@@ -1677,23 +1766,23 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
msg.rxFlush = 1;
msg.rxForward = 0;
msg.returnStatus = 0;
- msg.resetDataToggle = 0xff;
+ msg.resetDataToggle = 0;
msg.enablePort = 0;
- msg.disablePort = 0xff;
-
+ msg.disablePort = 1;
}
+ /* Sending intermediate configs */
else {
msg._txOn = (! p_priv->break_on);
msg._txOff = 0;
msg.txFlush = 0;
msg.txBreak = (p_priv->break_on);
- msg.rxOn = 1;
+ msg.rxOn = 0;
msg.rxOff = 0;
msg.rxFlush = 0;
msg.rxForward = 0;
msg.returnStatus = 0;
msg.resetDataToggle = 0x0;
- msg.enablePort = 0xff;
+ msg.enablePort = 0;
msg.disablePort = 0;
}
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index fc2c72e4a471..1d7c06b833ff 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -85,12 +85,20 @@ static struct usb_device_id skel_table [] = {
MODULE_DEVICE_TABLE (usb, skel_table);
-
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+/*
+ * if the user wants to use dynamic minor numbers, then we can have up to 256
+ * devices
+ */
+#define USB_SKEL_MINOR_BASE 0
+#define MAX_DEVICES 256
+#else
/* Get a minor range for your devices from the usb maintainer */
-#define USB_SKEL_MINOR_BASE 200
+#define USB_SKEL_MINOR_BASE 200
/* we can have up to this number of device plugged in at once */
#define MAX_DEVICES 16
+#endif
/* Structure to hold all of our device specific stuff */
struct usb_skel {
@@ -192,9 +200,6 @@ static struct usb_driver skel_driver = {
};
-
-
-
/**
* usb_skel_debug_data
*/
@@ -529,15 +534,17 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
return NULL;
}
- /* select a "subminor" number (part of a minor number) */
down (&minor_table_mutex);
- for (minor = 0; minor < MAX_DEVICES; ++minor) {
- if (minor_table[minor] == NULL)
- break;
- }
- if (minor >= MAX_DEVICES) {
- info ("Too many devices plugged in, can not handle this device.");
- goto exit;
+ if (usb_register_dev (&skel_driver, 1, &minor)) {
+ /* we could not get a dynamic minor, so lets find one of our own */
+ for (minor = 0; minor < MAX_DEVICES; ++minor) {
+ if (minor_table[minor] == NULL)
+ break;
+ }
+ if (minor >= MAX_DEVICES) {
+ info ("Too many devices plugged in, can not handle this device.");
+ goto exit;
+ }
}
/* allocate memory for our device state and intialize it */
@@ -642,8 +649,11 @@ static void skel_disconnect(struct usb_device *udev, void *ptr)
minor = dev->minor;
/* remove our devfs node */
- devfs_unregister(dev->devfs);
+ devfs_unregister (dev->devfs);
+ /* give back our dynamic minor */
+ usb_deregister_dev (&skel_driver, 1, minor);
+
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
up (&dev->sem);