diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Wed Mar 12 13:35:58 2003
+++ b/drivers/usb/serial/visor.c	Wed Mar 12 13:35:58 2003
@@ -2,7 +2,7 @@
  * USB HandSpring Visor, Palm m50x, and Sony Clie driver
  * (supports all of the Palm OS USB devices)
  *
- *	Copyright (C) 1999 - 2002
+ *	Copyright (C) 1999 - 2003
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -12,6 +12,20 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (03/09/2003) gkh
+ *	Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl
+ *	<brachtl@redgrep.cz> for the information.
+ *
+ * (3/07/2003) Adam Pennington <adamp@coed.org>
+ *      Backported version 2.1 of the driver from the 2.5 bitkeeper tree
+ *      making Treo actually work.
+ *
+ * (2/18/2003) Adam Powell <hazelsct at debian.org>
+ *	Backported 2.5 driver mods to support Handspring Treo.
+ *
+ * (2/11/2003) Adam Powell <hazelsct at debian.org>
+ *	Added device and vendor ids for the Samsung I330 phone.
+ *
  * (04/03/2002) gkh
  *	Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
  *	<hiro@zob.ne.jp> for the information.
@@ -146,9 +160,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.6"
+#define DRIVER_VERSION "v1.7"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
-#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver"
+#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Treo, Sony Clié driver"
 
 /* function prototypes for a handspring visor */
 static int  visor_open		(struct usb_serial_port *port, struct file *filp);
@@ -164,21 +178,30 @@
 static void visor_set_termios	(struct usb_serial_port *port, struct termios *old_termios);
 static void visor_write_bulk_callback	(struct urb *urb);
 static void visor_read_bulk_callback	(struct urb *urb);
+static void visor_read_int_callback	(struct urb *urb);
 static int  clie_3_5_startup	(struct usb_serial *serial);
+static void treo_attach		(struct usb_serial *serial);
 
 
 static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
-	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
+	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -189,17 +212,24 @@
 
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
+	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -210,9 +240,9 @@
 /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */
 static struct usb_serial_device_type handspring_device = {
 	.owner =		THIS_MODULE,
-	.name =			"Handspring Visor / Palm 4.0 / Clié 4.x",
+	.name =			"Handspring Visor / Treo / Palm 4.0 / Clié 4.x",
 	.id_table =		id_table,
-	.num_interrupt_in =	0,
+	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
 	.num_bulk_out =		2,
 	.num_ports =		2,
@@ -229,6 +259,7 @@
 	.chars_in_buffer =	visor_chars_in_buffer,
 	.write_bulk_callback =	visor_write_bulk_callback,
 	.read_bulk_callback =	visor_read_bulk_callback,
+	.read_int_callback =	visor_read_int_callback,
 };
 
 /* device info for the Sony Clie OS version 3.5 */
@@ -301,9 +332,19 @@
 			   port->read_urb->transfer_buffer_length,
 			   visor_read_bulk_callback, port);
 	result = usb_submit_urb(port->read_urb);
-	if (result)
+	if (result) {
 		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+		goto exit;
+	}
 	
+	if (port->interrupt_in_urb) {
+		dbg("%s - adding interrupt input for treo", __FUNCTION__);
+		result = usb_submit_urb(port->interrupt_in_urb);
+		if (result)
+			err("%s - failed submitting interrupt urb, error %d\n",
+			    __FUNCTION__, result);
+	}
+exit:
 	return result;
 }
 
@@ -322,6 +363,9 @@
 	if (!serial)
 		return;
 	
+
+
+
 	if (serial->dev) {
 		/* only send a shutdown message if the 
 		 * device is still here */
@@ -337,11 +381,25 @@
 					 transfer_buffer, 0x12, 300);
 			kfree (transfer_buffer);
 		}
-		/* shutdown our bulk read */
+
+		/* shutdown our urbs */
 		usb_unlink_urb (port->read_urb);
+		if (port->interrupt_in_urb)
+		  usb_unlink_urb (port->interrupt_in_urb);
+		/* Try to send shutdown message, if the device is gone, this will just fail. */
+		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+		if (transfer_buffer) {
+		  usb_control_msg (serial->dev,
+				 usb_rcvctrlpipe(serial->dev, 0),
+				 VISOR_CLOSE_NOTIFICATION, 0xc2,
+				 0x0000, 0x0000, 
+				 transfer_buffer, 0x12, 300);
+		kfree (transfer_buffer);			
+		
+		}
 	}
 	/* Uncomment the following line if you want to see some statistics in your syslog */
-	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+	info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out);
 }
 
 
@@ -538,6 +596,40 @@
 }
 
 
+static void visor_read_int_callback (struct urb *urb)
+{
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	/*
+	 * This information is still unknown what it can be used for.
+	 * If anyone has an idea, please let the author know...
+	 *
+	 * Rumor has it this endpoint is used to notify when data
+	 * is ready to be read from the bulk ones.
+	 */
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length,
+			       urb->transfer_buffer);
+
+exit:
+	return;
+}
+
+
 static void visor_throttle (struct usb_serial_port *port)
 {
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -561,30 +653,49 @@
 {
 	int response;
 	int i;
-	unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
-
-	if (!transfer_buffer) {
-		err("%s - kmalloc(%d) failed.", __FUNCTION__, 256);
-		return -ENOMEM;
-	}
+	unsigned char *transfer_buffer;
 
 	dbg("%s", __FUNCTION__);
 
 	dbg("%s - Set config to 1", __FUNCTION__);
 	usb_set_configuration (serial->dev, 1);
 
-	/* send a get connection info request */
-	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
-					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
-	if (response < 0) {
-		err("%s - error getting connection information", __FUNCTION__);
-	} else {
-		struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
+	if ((serial->dev->descriptor.idVendor == HANDSPRING_VENDOR_ID) &&
+	    (serial->dev->descriptor.idProduct == HANDSPRING_VISOR_ID)) {
+		struct visor_connection_info *connection_info;
 		char *string;
+		int num_ports;
+
+		transfer_buffer = kmalloc (sizeof (*connection_info),
+					   GFP_KERNEL);
+		if (!transfer_buffer) {
+			err("%s - kmalloc(%d) failed.", __FUNCTION__,
+			    sizeof (*connection_info));
+			return -ENOMEM;
+		}
 
+		/* send a get connection info request */
+		response = usb_control_msg (serial->dev,
+					    usb_rcvctrlpipe(serial->dev, 0),
+					    VISOR_GET_CONNECTION_INFORMATION,
+					    0xc2, 0x0000, 0x0000,
+					    transfer_buffer,
+					    sizeof (*connection_info), 300);
+		if (response < 0) {
+			err("%s - error getting connection information",
+			    __FUNCTION__);
+			goto exit;
+		}
+
+		connection_info = (struct visor_connection_info *)transfer_buffer;
 		le16_to_cpus(&connection_info->num_ports);
+		num_ports = connection_info->num_ports;
+
+		/* handle devices that report invalid stuff here */
+		if (num_ports > 2)
+			num_ports = 2;
 		info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
-		for (i = 0; i < connection_info->num_ports; ++i) {
+		for (i = 0; i < num_ports; ++i) {
 			switch (connection_info->connections[i].port_function_id) {
 				case VISOR_FUNCTION_GENERIC:
 					string = "Generic";
@@ -608,32 +719,32 @@
 			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name,
 			     connection_info->connections[i].port, string, serial->minor + i);
 		}
-	}
+	} else {
+		struct palm_ext_connection_info *connection_info;
 
-	if ((serial->dev->descriptor.idVendor == PALM_VENDOR_ID) ||
-	    ((serial->dev->descriptor.idVendor == SONY_VENDOR_ID) &&
-	     (serial->dev->descriptor.idProduct != SONY_CLIE_4_1_ID))) {
-		/* Palm OS 4.0 Hack */
-		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
-					    PALM_GET_SOME_UNKNOWN_INFORMATION,
-					    0xc2, 0x0000, 0x0000, transfer_buffer, 
-					    0x14, 300);
-		if (response < 0) {
-			err("%s - error getting first unknown palm command", __FUNCTION__);
-		} else {
-			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
+		transfer_buffer = kmalloc (sizeof (*connection_info),
+					   GFP_KERNEL);
+		if (!transfer_buffer) {
+			err("%s - kmalloc(%d) failed.", __FUNCTION__,
+			    sizeof (*connection_info));
+			return -ENOMEM;
 		}
+
 		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
-					    PALM_GET_SOME_UNKNOWN_INFORMATION,
+					    PALM_GET_EXT_CONNECTION_INFORMATION,
 					    0xc2, 0x0000, 0x0000, transfer_buffer, 
-					    0x14, 300);
+					    sizeof (*connection_info), 300);
 		if (response < 0) {
-			err("%s - error getting second unknown palm command", __FUNCTION__);
+			err("%s - error %d getting connection info",
+			    __FUNCTION__, response);
 		} else {
 			usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
 		}
 	}
 
+	/* Do our horrible Treo hack, if we should */
+	treo_attach(serial);
+
 	/* ask for the number of bytes available, but ignore the response as it is broken */
 	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
 					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
@@ -641,6 +752,7 @@
 		err("%s - error getting bytes available request", __FUNCTION__);
 	}
 
+exit:
 	kfree (transfer_buffer);
 
 	/* continue on with initialization */
@@ -688,6 +800,46 @@
 	return 0;
 }
 
+static void treo_attach (struct usb_serial *serial)
+{
+	struct usb_serial_port *port;
+	int i;
+
+	/* Only do this endpoint hack for the Handspring devices with
+	 * interrupt in endpoints, which for now are the Treo devices. */
+	if ((serial->dev->descriptor.idVendor != HANDSPRING_VENDOR_ID) ||
+	    (serial->num_interrupt_in == 0))
+		return;
+
+	dbg("%s", __FUNCTION__);
+
+	/* Ok, this is pretty ugly, but these devices want to use the
+	 * interrupt endpoint as paired up with a bulk endpoint for a
+	 * "virtual serial port".  So let's force the endpoints to be
+	 * where we want them to be. */
+	for (i = serial->num_bulk_in; i < serial->num_ports; ++i) {
+		port = &serial->port[i];
+		port->read_urb = serial->port[0].read_urb;
+		port->bulk_in_endpointAddress = serial->port[0].bulk_in_endpointAddress;
+		port->bulk_in_buffer = serial->port[0].bulk_in_buffer;
+	}
+
+	for (i = serial->num_bulk_out; i < serial->num_ports; ++i) {
+		port = &serial->port[i];
+		port->write_urb = serial->port[0].write_urb;
+		port->bulk_out_size = serial->port[0].bulk_out_size;
+		port->bulk_out_endpointAddress = serial->port[0].bulk_out_endpointAddress;
+		port->bulk_out_buffer = serial->port[0].bulk_out_buffer;
+	}
+
+	for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) {
+		port = &serial->port[i];
+		port->interrupt_in_urb = serial->port[0].interrupt_in_urb;
+		port->interrupt_in_endpointAddress = serial->port[0].interrupt_in_endpointAddress;
+		port->interrupt_in_buffer = serial->port[0].interrupt_in_buffer;
+ 	}
+}
+
 static void visor_shutdown (struct usb_serial *serial)
 {
 	dbg("%s", __FUNCTION__);
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Wed Mar 12 13:35:47 2003
+++ b/drivers/usb/serial/visor.h	Wed Mar 12 13:35:47 2003
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *	Copyright (C) 1999 - 2002
+ *	Copyright (C) 1999 - 2003
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
 
 #define HANDSPRING_VENDOR_ID		0x082d
 #define HANDSPRING_VISOR_ID		0x0100
+#define HANDSPRING_TREO_ID		0x0200
 
 #define PALM_VENDOR_ID			0x0830
 #define PALM_M500_ID			0x0001
@@ -27,13 +28,21 @@
 #define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
+#define PALM_TUNGSTEN_T_ID		0x0060
+#define PALM_TUNGSTEN_Z_ID		0x0031
 #define PALM_ZIRE_ID			0x0070
+#define PALM_M100_ID			0x0080
 
 #define SONY_VENDOR_ID			0x054C
 #define SONY_CLIE_3_5_ID		0x0038
 #define SONY_CLIE_4_0_ID		0x0066
 #define SONY_CLIE_S360_ID		0x0095
 #define SONY_CLIE_4_1_ID		0x009A
+#define SONY_CLIE_NX60_ID		0x00DA
+#define SONY_CLIE_NZ90V_ID		0x00E9
+
+#define SAMSUNG_VENDOR_ID		0x04E8
+#define SAMSUNG_SCH_I330_ID		0x8001
 
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
@@ -90,7 +99,36 @@
  * PALM_GET_SOME_UNKNOWN_INFORMATION is sent by the host during enumeration to
  * get some information from the M series devices, that is currently unknown.
  ****************************************************************************/
-#define PALM_GET_SOME_UNKNOWN_INFORMATION	0x04
+#define PALM_GET_EXT_CONNECTION_INFORMATION	0x04
+
+/**
+ * struct palm_ext_connection_info - return data from a PALM_GET_EXT_CONNECTION_INFORMATION request
+ * @num_ports: maximum number of functions/connections in use
+ * @endpoint_numbers_different: will be 1 if in and out endpoints numbers are
+ *	different, otherwise it is 0.  If value is 1, then
+ *	connections.end_point_info is non-zero.  If value is 0, then
+ *	connections.port contains the endpoint number, which is the same for in
+ *	and out.
+ * @port_function_id: contains the creator id of the applicaton that opened
+ *	this connection.
+ * @port: contains the in/out endpoint number.  Is 0 if in and out endpoint
+ *	numbers are different.
+ * @end_point_info: high nubbe is in endpoint and low nibble will indicate out
+ *	endpoint.  Is 0 if in and out endpoints are the same.
+ *
+ * The maximum number of connections currently supported is 2
+ */
+struct palm_ext_connection_info {
+	__u8 num_ports;		
+	__u8 endpoint_numbers_different;
+	__u16 reserved1;
+	struct {
+		__u32 port_function_id;
+		__u8 port;
+		__u8 end_point_info;
+		__u16 reserved;
+	} connections[2];
+};
 
 #endif
 
