# 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.485   -> 1.486  
#	drivers/usb/serial/usbserial.c	1.32    -> 1.33   
#	drivers/usb/serial/usb-serial.h	1.9     -> 1.10   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/14	greg@kroah.com	1.486
# USB: usb-serial api changes
# 	- added calc_num_ports() callback so that driver can override the
# 	  fixed num_ports value after querying the device.
# 	- split startup() callback into probe() and attach() in anticipation
# 	  of the driverfs api changes
# 	- probe() is called before the usb_serial structure is set up,
# 	  and can be used to download firmware to a device, and other
# 	  early initialization.
# 	- attach() is called after the usb_serial structure is completely
# 	  setup, allowing the device to create private structures, and
# 	  have full access to the device.
# --------------------------------------------
#
diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
--- a/drivers/usb/serial/usb-serial.h	Fri Jun 14 14:15:26 2002
+++ b/drivers/usb/serial/usb-serial.h	Fri Jun 14 14:15:26 2002
@@ -130,9 +130,20 @@
  * @num_bulk_in: the number of bulk in endpoints this device will have.
  * @num_bulk_out: the number of bulk out endpoints this device will have.
  * @num_ports: the number of different ports this device will have.
- * @startup: pointer to the driver's startup function.  This will be called
- *	when the driver is inserted into the system.  Return 0 to continue
- *	on with the initialization sequence.  Anything else will abort it.
+ * @calc_num_ports: pointer to a function to determine how many ports this
+ *	device has dynamically.  It will be called after the probe()
+ *	callback is called, but before attach()
+ * @probe: pointer to the driver's probe function.
+ *	This will be called when the device is inserted into the system,
+ *	but before the device has been fully initialized by the usb_serial
+ *	subsystem.  Use this function to download any firmware to the device,
+ *	or any other early initialization that might be needed.
+ *	Return 0 to continue on with the initialization sequence.  Anything 
+ *	else will abort it.
+ * @attach: pointer to the driver's attach function.
+ *	This will be called when the struct usb_serial structure is fully set
+ *	set up.  Do any local initialization of the device, or any private
+ *	memory structure allocation at this point in time.
  * @shutdown: pointer to the driver's shutdown function.  This will be
  *	called when the device is removed from the system.
  *
@@ -153,7 +164,10 @@
 
 	struct list_head	driver_list;
 	
-	int (*startup) (struct usb_serial *serial);
+	int (*probe) (struct usb_serial *serial);
+	int (*attach) (struct usb_serial *serial);
+	int (*calc_num_ports) (struct usb_serial *serial);
+
 	void (*shutdown) (struct usb_serial *serial);
 
 	/* serial function calls */
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Fri Jun 14 14:15:26 2002
+++ b/drivers/usb/serial/usbserial.c	Fri Jun 14 14:15:26 2002
@@ -433,9 +433,8 @@
 	return serial_table[minor];
 }
 
-static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor)
+static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
 {
-	struct usb_serial *serial = NULL;
 	unsigned int i, j;
 	int good_spot;
 
@@ -453,11 +452,14 @@
 		if (good_spot == 0)
 			continue;
 			
-		if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
-			err(__FUNCTION__ " - Out of memory");
-			return NULL;
+		if (!serial) {
+			serial = kmalloc(sizeof(*serial), GFP_KERNEL);
+			if (!serial) {
+				err(__FUNCTION__ " - Out of memory");
+				return NULL;
+			}
+			memset(serial, 0, sizeof(*serial));
 		}
-		memset(serial, 0, sizeof(struct usb_serial));
 		serial->magic = USB_SERIAL_MAGIC;
 		serial_table[i] = serial;
 		*minor = i;
@@ -1140,6 +1142,27 @@
 	wake_up_interruptible(&tty->write_wait);
 }
 
+static struct usb_serial * create_serial (struct usb_device *dev, 
+					  struct usb_interface *interface,
+					  struct usb_serial_device_type *type)
+{
+	struct usb_serial *serial;
+
+	serial = kmalloc (sizeof (*serial), GFP_KERNEL);
+	if (!serial) {
+		err ("%s - out of memory", __FUNCTION__);
+		return NULL;
+	}
+	memset (serial, 0, sizeof(*serial));
+	serial->dev = dev;
+	serial->type = type;
+	serial->interface = interface;
+	serial->vendor = dev->descriptor.idVendor;
+	serial->product = dev->descriptor.idProduct;
+
+	return serial;
+}
+
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
 			       const struct usb_device_id *id)
 {
@@ -1161,7 +1184,7 @@
 	int num_interrupt_in = 0;
 	int num_bulk_in = 0;
 	int num_bulk_out = 0;
-	int num_ports;
+	int num_ports = 0;
 	int max_endpoints;
 	const struct usb_device_id *id_pattern = NULL;
 
@@ -1184,6 +1207,27 @@
 		return(NULL);
 	}
 
+	/* if this device type has a probe function, call it */
+	if (type->probe) {
+		serial = create_serial (dev, interface, type);
+		if (!serial) {
+			err ("%s - out of memory", __FUNCTION__);
+			return NULL;
+		}
+
+		if (type->owner)
+			__MOD_INC_USE_COUNT(type->owner);
+		retval = type->probe (serial);
+		if (type->owner)
+			__MOD_DEC_USE_COUNT(type->owner);
+
+		if (retval < 0) {
+			dbg ("sub driver rejected device");
+			kfree (serial);
+			return NULL;
+		}
+	}
+
 	/* descriptor matches, let's find the endpoints needed */
 	/* check out the endpoints */
 	iface_desc = &interface->altsetting[0];
@@ -1251,11 +1295,30 @@
 			err("Generic device with no bulk out, not allowed.");
 			return NULL;
 		}
-	} else
+	}
 #endif
-		num_ports = type->num_ports;
+	if (!num_ports) {
+		/* if this device type has a calc_num_ports function, call it */
+		if (type->calc_num_ports) {
+			if (!serial) {
+				serial = create_serial (dev, interface, type);
+				if (!serial) {
+					err ("%s - out of memory", __FUNCTION__);
+					return NULL;
+				}
+			}
 
-	serial = get_free_serial (num_ports, &minor);
+			if (type->owner)
+				__MOD_INC_USE_COUNT(type->owner);
+			num_ports = type->calc_num_ports (serial);
+			if (type->owner)
+				__MOD_DEC_USE_COUNT(type->owner);
+		}
+		if (!num_ports)
+			num_ports = type->num_ports;
+	}
+
+	serial = get_free_serial (serial, num_ports, &minor);
 	if (serial == NULL) {
 		err("No more free serial devices");
 		return NULL;
@@ -1272,17 +1335,6 @@
 	serial->vendor = dev->descriptor.idVendor;
 	serial->product = dev->descriptor.idProduct;
 
-	/* if this device type has a startup function, call it */
-	if (type->startup) {
-		if (type->owner)
-			__MOD_INC_USE_COUNT(type->owner);
-		retval = type->startup (serial);
-		if (type->owner)
-			__MOD_DEC_USE_COUNT(type->owner);
-		if (retval)
-			goto probe_error;
-	}
-
 	/* set up the endpoint information */
 	for (i = 0; i < num_bulk_in; ++i) {
 		endpoint = bulk_in_endpoint[i];
@@ -1372,6 +1424,22 @@
 		port->tqueue.routine = port_softint;
 		port->tqueue.data = port;
 		init_MUTEX (&port->sem);
+	}
+
+	/* if this device type has an attach function, call it */
+	if (type->attach) {
+		if (type->owner)
+			__MOD_INC_USE_COUNT(type->owner);
+		retval = type->attach (serial);
+		if (type->owner)
+			__MOD_DEC_USE_COUNT(type->owner);
+		if (retval < 0)
+			goto probe_error;
+		if (retval > 0) {
+			/* quietly accept this device, but don't bind to a serial port
+			 * as it's about to disappear */
+			return serial;
+		}
 	}
 
 	/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
