LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] visor: Fix Oops on disconnect
@ 2004-05-20 23:08 nardelli
  2004-05-21  4:30 ` [linux-usb-devel] " Greg KH
  2004-05-21  4:31 ` Greg KH
  0 siblings, 2 replies; 26+ messages in thread
From: nardelli @ 2004-05-20 23:08 UTC (permalink / raw)
  To: linux-kernel, linux-usb-devel

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

Here is a proposed patch for Oops on disconnect in the visor module.
For details of the problem, please see
http://bugzilla.kernel.org/show_bug.cgi?id=2289

I would really appreciate it if anyone that uses this module could please
try this patch to make sure that it works as intended.  Also, as this is
the first patch that I've submitted, please feel free to be brutally
honest regarding content, formatting, etc.



-- 
Joe Nardelli
jnardelli@infosciences.com

[-- Attachment #2: patch.treo --]
[-- Type: text/plain, Size: 8607 bytes --]

--- old/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
+++ new/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400
@@ -12,6 +12,13 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (5/20/2004) Joe Nardelli
+ *	Reduced possibility for unitialized data access in palm_os_3_probe.
+ *	Modified workaround for treo endpoint setup in treo_attach.
+ *	Removed assumptions that port->read_urb was always valid (is not true
+ *	for usb serial devices with more bulk out or interrupt endpoints than
+ *	bulk in endpoints).
+ *
  * (06/03/2003) Judd Montgomery <judd at jpilot.org>
  *     Added support for module parameter options for untested/unknown
  *     devices.
@@ -398,7 +405,8 @@
 	
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->read_urb) {
+	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
+	{
 		/* this is needed for some brain dead Sony devices */
 		dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
 		return -ENODEV;
@@ -416,17 +424,19 @@
 		port->tty->low_latency = 1;
 
 	/* Start reading from the device */
-	usb_fill_bulk_urb (port->read_urb, serial->dev,
-			   usb_rcvbulkpipe (serial->dev, 
-					    port->bulk_in_endpointAddress),
-			   port->read_urb->transfer_buffer,
-			   port->read_urb->transfer_buffer_length,
-			   visor_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result) {
-		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n",
-			__FUNCTION__, result);
-		goto exit;
+	if (port->read_urb) {
+		usb_fill_bulk_urb (port->read_urb, serial->dev,
+			usb_rcvbulkpipe (serial->dev, 
+				port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			visor_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+		if (result) {
+			dev_err(&port->dev, "%s - failed submitting read urb, error %d\n",
+				__FUNCTION__, result);
+			goto exit;
+		}
 	}
 	
 	if (port->interrupt_in_urb) {
@@ -456,7 +466,8 @@
 		return;
 	
 	/* shutdown our urbs */
-	usb_unlink_urb (port->read_urb);
+	if (port->read_urb)
+		usb_unlink_urb (port->read_urb);
 	if (port->interrupt_in_urb)
 		usb_unlink_urb (port->interrupt_in_urb);
 
@@ -622,15 +633,18 @@
 	bytes_in += urb->actual_length;
 
 	/* Continue trying to always read  */
-	usb_fill_bulk_urb (port->read_urb, serial->dev,
-			   usb_rcvbulkpipe (serial->dev,
-					    port->bulk_in_endpointAddress),
-			   port->read_urb->transfer_buffer,
-			   port->read_urb->transfer_buffer_length,
-			   visor_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+	if (port->read_urb) {
+		usb_fill_bulk_urb (port->read_urb, serial->dev,
+			usb_rcvbulkpipe (serial->dev,
+			port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			visor_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+		if (result)
+			dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+	}
+  
 	return;
 }
 
@@ -675,7 +689,9 @@
 static void visor_throttle (struct usb_serial_port *port)
 {
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	usb_unlink_urb (port->read_urb);
+	if (port->read_urb) {
+		usb_unlink_urb (port->read_urb);
+	}
 }
 
 
@@ -685,10 +701,12 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+	if (port->read_urb) {
+		port->read_urb->dev = port->serial->dev;
+		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+		if (result)
+			dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+	}
 }
 
 static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id)
@@ -710,6 +728,13 @@
 		return -ENOMEM;
 	}
 
+	/*
+	* We don't know how much data gets written into transfer_buffer, so let's
+	* at least set it all to 0 to avoid putting random data into num_ports
+	* (which causes unitialized, and possibly unallocated data to be accessed)
+	*/
+	memset (transfer_buffer, 0, sizeof(*connection_info));
+  
 	/* send a get connection info request */
 	retval = usb_control_msg (serial->dev,
 				  usb_rcvctrlpipe(serial->dev, 0),
@@ -726,11 +751,20 @@
 
 	le16_to_cpus(&connection_info->num_ports);
 	num_ports = connection_info->num_ports;
-	/* handle devices that report invalid stuff here */
-	if (num_ports > 2)
+	/*
+	* Handle devices that report invalid stuff here.  I think that this will
+	* work for both big and little endian architectures that do not report
+	* back valid connect info, but I'd still like to verify this on a big
+	* endian machine.  Any testers?
+	*/
+	if (num_ports <= 0 || num_ports > 2) {
+		dev_warn (dev, "%s: No valid connect info available\n",
+			serial->type->name);
 		num_ports = 2;
+	}
+  
 	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
-		connection_info->num_ports);
+		num_ports);
 
 	for (i = 0; i < num_ports; ++i) {
 		switch (connection_info->connections[i].port_function_id) {
@@ -887,8 +921,7 @@
  
 static int treo_attach (struct usb_serial *serial)
 {
-	struct usb_serial_port *port;
-	int i;
+	struct usb_serial_port swap_port;
 
 	/* Only do this endpoint hack for the Handspring devices with
 	 * interrupt in endpoints, which for now are the Treo devices. */
@@ -898,31 +931,32 @@
 
 	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;
-	}
+	/*
+	* It appears that Treos want to use the 1st interrupt endpoint to communicate
+	* with the 2nd bulk out endpoint, so let's swap the 1st and 2nd bulk in
+	* and interrupt endpoints.  Note that swapping the bulk out endpoints would
+	* break lots of apps that want to communicate on the second port.
+	*/
+	swap_port.read_urb = serial->port[0]->read_urb;
+	swap_port.bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
+	swap_port.bulk_in_buffer = serial->port[0]->bulk_in_buffer;
+	swap_port.interrupt_in_urb = serial->port[0]->interrupt_in_urb;
+	swap_port.interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
+	swap_port.interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
+ 
+	serial->port[0]->read_urb = serial->port[1]->read_urb;
+	serial->port[0]->bulk_in_endpointAddress = serial->port[1]->bulk_in_endpointAddress;
+	serial->port[0]->bulk_in_buffer = serial->port[1]->bulk_in_buffer;
+	serial->port[0]->interrupt_in_urb = serial->port[1]->interrupt_in_urb;
+	serial->port[0]->interrupt_in_endpointAddress = serial->port[1]->interrupt_in_endpointAddress;
+	serial->port[0]->interrupt_in_buffer = serial->port[1]->interrupt_in_buffer;
+
+	serial->port[1]->read_urb = swap_port.read_urb;
+	serial->port[1]->bulk_in_endpointAddress = swap_port.bulk_in_endpointAddress;
+	serial->port[1]->bulk_in_buffer = swap_port.bulk_in_buffer;
+	serial->port[1]->interrupt_in_urb = swap_port.interrupt_in_urb;
+	serial->port[1]->interrupt_in_endpointAddress = swap_port.interrupt_in_endpointAddress;
+	serial->port[1]->interrupt_in_buffer = swap_port.interrupt_in_buffer;
 
 	return 0;
 }

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-20 23:08 [PATCH] visor: Fix Oops on disconnect nardelli
@ 2004-05-21  4:30 ` Greg KH
  2004-05-21  5:03   ` Pete Zaitcev
                     ` (2 more replies)
  2004-05-21  4:31 ` Greg KH
  1 sibling, 3 replies; 26+ messages in thread
From: Greg KH @ 2004-05-21  4:30 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Thu, May 20, 2004 at 07:08:56PM -0400, nardelli wrote:
> Here is a proposed patch for Oops on disconnect in the visor module.
> For details of the problem, please see
> http://bugzilla.kernel.org/show_bug.cgi?id=2289
> 
> I would really appreciate it if anyone that uses this module could please
> try this patch to make sure that it works as intended.  Also, as this is
> the first patch that I've submitted, please feel free to be brutally
> honest regarding content, formatting, etc.

Ok, I'll be brutal, but remember, you asked :)

First off, read Documentation/SubmittingPatches and
Documentation/CodingStyle to see the proper way to make patches, and how
to format the code.

> --- old/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
> +++ new/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400

I need to be able to apply this patch by using a -p1 in the kernel
directory.  So the patch should be one directory up and look like:

--- linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
+++ linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400


> @@ -12,6 +12,13 @@
>   *
>   * See Documentation/usb/usb-serial.txt for more information on using this driver
>   *
> + * (5/20/2004) Joe Nardelli
> + *	Reduced possibility for unitialized data access in palm_os_3_probe.
> + *	Modified workaround for treo endpoint setup in treo_attach.
> + *	Removed assumptions that port->read_urb was always valid (is not true
> + *	for usb serial devices with more bulk out or interrupt endpoints than
> + *	bulk in endpoints).

I'm trying not to add new stuff to the changelog at the beginning of the
file, but this is not really a big deal.

> -	if (!port->read_urb) {
> +	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
> +	{

Wrong formatting style for the '{'

Your patch says that we might not have a read_urb for the given port?
How could that be true?  The check here in open() will catch any devices
that this might not be correct for.  So that portion of this patch is
not needed, right?

>  static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id)
> @@ -710,6 +728,13 @@
>  		return -ENOMEM;
>  	}
>  
> +	/*
> +	* We don't know how much data gets written into transfer_buffer, so let's
> +	* at least set it all to 0 to avoid putting random data into num_ports
> +	* (which causes unitialized, and possibly unallocated data to be accessed)
> +	*/
> +	memset (transfer_buffer, 0, sizeof(*connection_info));

Um, we ask for a set ammount of data, and we should get it.  But we
should check the size of the data returned to make sure of this, right?

>  	/* send a get connection info request */
>  	retval = usb_control_msg (serial->dev,
>  				  usb_rcvctrlpipe(serial->dev, 0),
> @@ -726,11 +751,20 @@
>  
>  	le16_to_cpus(&connection_info->num_ports);
>  	num_ports = connection_info->num_ports;
> -	/* handle devices that report invalid stuff here */
> -	if (num_ports > 2)
> +	/*
> +	* Handle devices that report invalid stuff here.  I think that this will
> +	* work for both big and little endian architectures that do not report
> +	* back valid connect info, but I'd still like to verify this on a big
> +	* endian machine.  Any testers?
> +	*/

The call above to le16_to_cpus() will handle the endian issue here.
This comment can be removed.

> +	if (num_ports <= 0 || num_ports > 2) {

I like the idea of this check, but you are trying to test for a negative
value on a __u16 variable, which is always unsigned.  So that check will
never be true :)

> +		dev_warn (dev, "%s: No valid connect info available\n",
> +			serial->type->name);
>  		num_ports = 2;
> +	}
> +  
>  	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
> -		connection_info->num_ports);
> +		num_ports);
>  
>  	for (i = 0; i < num_ports; ++i) {
>  		switch (connection_info->connections[i].port_function_id) {
> @@ -887,8 +921,7 @@
>   
>  static int treo_attach (struct usb_serial *serial)
>  {
> -	struct usb_serial_port *port;
> -	int i;
> +	struct usb_serial_port swap_port;
>  
>  	/* Only do this endpoint hack for the Handspring devices with
>  	 * interrupt in endpoints, which for now are the Treo devices. */
> @@ -898,31 +931,32 @@
>  
>  	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;
> -	}
> +	/*
> +	* It appears that Treos want to use the 1st interrupt endpoint to communicate
> +	* with the 2nd bulk out endpoint, so let's swap the 1st and 2nd bulk in
> +	* and interrupt endpoints.  Note that swapping the bulk out endpoints would
> +	* break lots of apps that want to communicate on the second port.
> +	*/
> +	swap_port.read_urb = serial->port[0]->read_urb;
> +	swap_port.bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
> +	swap_port.bulk_in_buffer = serial->port[0]->bulk_in_buffer;
> +	swap_port.interrupt_in_urb = serial->port[0]->interrupt_in_urb;
> +	swap_port.interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
> +	swap_port.interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
> + 
> +	serial->port[0]->read_urb = serial->port[1]->read_urb;
> +	serial->port[0]->bulk_in_endpointAddress = serial->port[1]->bulk_in_endpointAddress;
> +	serial->port[0]->bulk_in_buffer = serial->port[1]->bulk_in_buffer;
> +	serial->port[0]->interrupt_in_urb = serial->port[1]->interrupt_in_urb;
> +	serial->port[0]->interrupt_in_endpointAddress = serial->port[1]->interrupt_in_endpointAddress;
> +	serial->port[0]->interrupt_in_buffer = serial->port[1]->interrupt_in_buffer;
> +
> +	serial->port[1]->read_urb = swap_port.read_urb;
> +	serial->port[1]->bulk_in_endpointAddress = swap_port.bulk_in_endpointAddress;
> +	serial->port[1]->bulk_in_buffer = swap_port.bulk_in_buffer;
> +	serial->port[1]->interrupt_in_urb = swap_port.interrupt_in_urb;
> +	serial->port[1]->interrupt_in_endpointAddress = swap_port.interrupt_in_endpointAddress;
> +	serial->port[1]->interrupt_in_buffer = swap_port.interrupt_in_buffer;

Now this is the meat of the patch.  Is that all that is needed, just
swaping the info?  That makes more sense than the hack of assigning the
same port data to both ports.  Does this work properly on disconnect
too?

Thanks a lot for doing this, with some cleanups I'll be glad to accept
this patch.

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-20 23:08 [PATCH] visor: Fix Oops on disconnect nardelli
  2004-05-21  4:30 ` [linux-usb-devel] " Greg KH
@ 2004-05-21  4:31 ` Greg KH
  1 sibling, 0 replies; 26+ messages in thread
From: Greg KH @ 2004-05-21  4:31 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Thu, May 20, 2004 at 07:08:56PM -0400, nardelli wrote:
> Here is a proposed patch for Oops on disconnect in the visor module.
> For details of the problem, please see
> http://bugzilla.kernel.org/show_bug.cgi?id=2289
> 
> I would really appreciate it if anyone that uses this module could please
> try this patch to make sure that it works as intended.  Also, as this is
> the first patch that I've submitted, please feel free to be brutally
> honest regarding content, formatting, etc.

Oops, one other thing, you should CC: the driver author/maintainer too,
so they know what you are trying to do.  Don't assume they will see your
patch on a mailing list :)

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21  4:30 ` [linux-usb-devel] " Greg KH
@ 2004-05-21  5:03   ` Pete Zaitcev
  2004-05-21 14:52     ` nardelli
  2004-05-21 14:48   ` nardelli
  2004-05-21 19:51   ` nardelli
  2 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2004-05-21  5:03 UTC (permalink / raw)
  To: Greg KH; +Cc: jnardelli, linux-kernel, linux-usb-devel

On Thu, 20 May 2004 21:30:32 -0700
Greg KH <greg@kroah.com> wrote:

> > -	if (!port->read_urb) {
> > +	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
> > +	{

> Your patch says that we might not have a read_urb for the given port?
> How could that be true?  The check here in open() will catch any devices
> that this might not be correct for.  So that portion of this patch is
> not needed, right?

I know nothing about Palms, but also that part contradicted a comment.

-	if (!port->read_urb) {
+	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
+	{
 		/* this is needed for some brain dead Sony devices */

So.... the patch makes the body of the if to be used when it's NOT Sony,
but the comment says that it's intended for Sony. I think it's fishy.

-- Pete

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21  4:30 ` [linux-usb-devel] " Greg KH
  2004-05-21  5:03   ` Pete Zaitcev
@ 2004-05-21 14:48   ` nardelli
  2004-05-21 15:05     ` Alan Stern
  2004-05-21 15:41     ` Greg KH
  2004-05-21 19:51   ` nardelli
  2 siblings, 2 replies; 26+ messages in thread
From: nardelli @ 2004-05-21 14:48 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> On Thu, May 20, 2004 at 07:08:56PM -0400, nardelli wrote:
> 
>>Here is a proposed patch for Oops on disconnect in the visor module.
>>For details of the problem, please see
>>http://bugzilla.kernel.org/show_bug.cgi?id=2289
>>
>>I would really appreciate it if anyone that uses this module could please
>>try this patch to make sure that it works as intended.  Also, as this is
>>the first patch that I've submitted, please feel free to be brutally
>>honest regarding content, formatting, etc.
> 
> 
> Ok, I'll be brutal, but remember, you asked :)
> 
> First off, read Documentation/SubmittingPatches and
> Documentation/CodingStyle to see the proper way to make patches, and how
> to format the code.
> 

I'll reformat/regenerate patch.

> 
>>--- old/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
>>+++ new/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400
> 
> 
> I need to be able to apply this patch by using a -p1 in the kernel
> directory.  So the patch should be one directory up and look like:
> 
> --- linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
> +++ linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400
> 
> 

I'll regenerate patch.

> 
>>@@ -12,6 +12,13 @@
>>  *
>>  * See Documentation/usb/usb-serial.txt for more information on using this driver
>>  *
>>+ * (5/20/2004) Joe Nardelli
>>+ *	Reduced possibility for unitialized data access in palm_os_3_probe.
>>+ *	Modified workaround for treo endpoint setup in treo_attach.
>>+ *	Removed assumptions that port->read_urb was always valid (is not true
>>+ *	for usb serial devices with more bulk out or interrupt endpoints than
>>+ *	bulk in endpoints).
> 
> 
> I'm trying not to add new stuff to the changelog at the beginning of the
> file, but this is not really a big deal.
> 
> 

It did seem like the change log was a little old :-).  The comments are at
bugzilla any way.  I'll remove it.


>>-	if (!port->read_urb) {
>>+	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
>>+	{
> 
> 
> Wrong formatting style for the '{'
> 

Will reformat.

> Your patch says that we might not have a read_urb for the given port?
> How could that be true?  The check here in open() will catch any devices
> that this might not be correct for.  So that portion of this patch is
> not needed, right?
> 
> 

The patch should be happy to let devices thru visor_open with no read_urb,
except for Sonys.

The old check would error out of visor_open() with -ENODEV if there was
not a read_urb for any device, and there was a comment that this was
needed for 'some brain dead Sony devices'.  I modified this to error out
only for Sony devices, instead of just a comment about them.  This
should not modify the behavior on Sonys, but may on others (namely treos).

I'd really like to know more about why some Sony devices do not have a
read_urb, but at least for now, I did not change functionality for them.

>> static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id)
>>@@ -710,6 +728,13 @@
>> 		return -ENOMEM;
>> 	}
>> 
>>+	/*
>>+	* We don't know how much data gets written into transfer_buffer, so let's
>>+	* at least set it all to 0 to avoid putting random data into num_ports
>>+	* (which causes unitialized, and possibly unallocated data to be accessed)
>>+	*/
>>+	memset (transfer_buffer, 0, sizeof(*connection_info));
> 
> 
> Um, we ask for a set ammount of data, and we should get it.  But we
> should check the size of the data returned to make sure of this, right?
> 
> 

The data being returned had unitialzed data in it.  Before doing a memset, I
almost always had 23130 ports, but that changed upon kernel build.  This
resulted in trying to access ALOT of bad memory.  After adding a memset,
no random data was showing up.  If this were outside of the kernel, I suspect
that would have resulted in a segmentation violation.

The api for usb_control_msg says, 'If successful, it returns 0, othwise a
negative error number', and I didn't see any other way to figure out how
much data was being returned.

I would definitely prefer to do a check on the amount of data being returned.
Any suggestions?

>> 	/* send a get connection info request */
>> 	retval = usb_control_msg (serial->dev,
>> 				  usb_rcvctrlpipe(serial->dev, 0),
>>@@ -726,11 +751,20 @@
>> 
>> 	le16_to_cpus(&connection_info->num_ports);
>> 	num_ports = connection_info->num_ports;
>>-	/* handle devices that report invalid stuff here */
>>-	if (num_ports > 2)
>>+	/*
>>+	* Handle devices that report invalid stuff here.  I think that this will
>>+	* work for both big and little endian architectures that do not report
>>+	* back valid connect info, but I'd still like to verify this on a big
>>+	* endian machine.  Any testers?
>>+	*/
> 
> 
> The call above to le16_to_cpus() will handle the endian issue here.
> This comment can be removed.
> 
> 

I'll drop it.

>>+	if (num_ports <= 0 || num_ports > 2) {
> 
> 
> I like the idea of this check, but you are trying to test for a negative
> value on a __u16 variable, which is always unsigned.  So that check will
> never be true :)
> 
> 

I just noticed that num_ports is defined as an int in palm_os_3_probe(), and
as __u16 in visor.c.  Would you like me to set the one in palm_os_3_probe()
to a __u16?

Either way, I'll change it to look for (num_ports == 0 || num_ports > 2).
With no conection data being returned for treos, it should report 0 ports.

>>+		dev_warn (dev, "%s: No valid connect info available\n",
>>+			serial->type->name);
>> 		num_ports = 2;
>>+	}
>>+  
>> 	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
>>-		connection_info->num_ports);
>>+		num_ports);
>> 
>> 	for (i = 0; i < num_ports; ++i) {
>> 		switch (connection_info->connections[i].port_function_id) {
>>@@ -887,8 +921,7 @@
>>  
>> static int treo_attach (struct usb_serial *serial)
>> {
>>-	struct usb_serial_port *port;
>>-	int i;
>>+	struct usb_serial_port swap_port;
>> 
>> 	/* Only do this endpoint hack for the Handspring devices with
>> 	 * interrupt in endpoints, which for now are the Treo devices. */
>>@@ -898,31 +931,32 @@
>> 
>> 	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;
>>-	}
>>+	/*
>>+	* It appears that Treos want to use the 1st interrupt endpoint to communicate
>>+	* with the 2nd bulk out endpoint, so let's swap the 1st and 2nd bulk in
>>+	* and interrupt endpoints.  Note that swapping the bulk out endpoints would
>>+	* break lots of apps that want to communicate on the second port.
>>+	*/
>>+	swap_port.read_urb = serial->port[0]->read_urb;
>>+	swap_port.bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
>>+	swap_port.bulk_in_buffer = serial->port[0]->bulk_in_buffer;
>>+	swap_port.interrupt_in_urb = serial->port[0]->interrupt_in_urb;
>>+	swap_port.interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
>>+	swap_port.interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
>>+ 
>>+	serial->port[0]->read_urb = serial->port[1]->read_urb;
>>+	serial->port[0]->bulk_in_endpointAddress = serial->port[1]->bulk_in_endpointAddress;
>>+	serial->port[0]->bulk_in_buffer = serial->port[1]->bulk_in_buffer;
>>+	serial->port[0]->interrupt_in_urb = serial->port[1]->interrupt_in_urb;
>>+	serial->port[0]->interrupt_in_endpointAddress = serial->port[1]->interrupt_in_endpointAddress;
>>+	serial->port[0]->interrupt_in_buffer = serial->port[1]->interrupt_in_buffer;
>>+
>>+	serial->port[1]->read_urb = swap_port.read_urb;
>>+	serial->port[1]->bulk_in_endpointAddress = swap_port.bulk_in_endpointAddress;
>>+	serial->port[1]->bulk_in_buffer = swap_port.bulk_in_buffer;
>>+	serial->port[1]->interrupt_in_urb = swap_port.interrupt_in_urb;
>>+	serial->port[1]->interrupt_in_endpointAddress = swap_port.interrupt_in_endpointAddress;
>>+	serial->port[1]->interrupt_in_buffer = swap_port.interrupt_in_buffer;
> 
> 
> Now this is the meat of the patch.  Is that all that is needed, just
> swaping the info?  That makes more sense than the hack of assigning the
> same port data to both ports.  Does this work properly on disconnect
> too?
> 

That and the memset are the meat of the patch.  Pretty simple, but it took
alot of coming up to speed on usb to try and interpret the output of usbsnoop.
There was some communication on the second (as reported by the device) bulk
out endpoint, but I couldn't figure out what that was doing.  I suspect that
some treo protocol specs would help with that, but I still haven't found any.

After more than 30 backups with jpilot, about 5 listings with pilot-xfer, and
about 5 where I disconnected the device in the middle of a transfer, I have yet
to encounter a problem.  I'd appreciate it others would test this patch after
I've made the changes described above.

> Thanks a lot for doing this, with some cleanups I'll be glad to accept
> this patch.
> 
> thanks,
> 
> greg k-h
> 
> 
> -------------------------------------------------------
> This SF.Net email is sponsored by: Oracle 10g
> Get certified on the hottest thing ever to hit the market... Oracle 10g. 
> Take an Oracle 10g class now, and we'll give you the exam FREE.
> http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
> _______________________________________________
> linux-usb-devel@lists.sourceforge.net
> To unsubscribe, use the last form field at:
> https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
> 


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21  5:03   ` Pete Zaitcev
@ 2004-05-21 14:52     ` nardelli
  0 siblings, 0 replies; 26+ messages in thread
From: nardelli @ 2004-05-21 14:52 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Greg KH, linux-kernel, linux-usb-devel

Pete Zaitcev wrote:
> On Thu, 20 May 2004 21:30:32 -0700
> Greg KH <greg@kroah.com> wrote:
> 
> 
>>>-	if (!port->read_urb) {
>>>+	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
>>>+	{
> 
> 
>>Your patch says that we might not have a read_urb for the given port?
>>How could that be true?  The check here in open() will catch any devices
>>that this might not be correct for.  So that portion of this patch is
>>not needed, right?
> 
> 
> I know nothing about Palms, but also that part contradicted a comment.
> 
> -	if (!port->read_urb) {
> +	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
> +	{
>  		/* this is needed for some brain dead Sony devices */
> 
> So.... the patch makes the body of the if to be used when it's NOT Sony,
> but the comment says that it's intended for Sony. I think it's fishy.

Oops - that does look a little fishy.  I'll revisit.

> 
> -- Pete
> 


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 14:48   ` nardelli
@ 2004-05-21 15:05     ` Alan Stern
  2004-05-21 17:08       ` nardelli
  2004-05-21 15:41     ` Greg KH
  1 sibling, 1 reply; 26+ messages in thread
From: Alan Stern @ 2004-05-21 15:05 UTC (permalink / raw)
  To: nardelli; +Cc: Greg KH, linux-kernel, linux-usb-devel

On Fri, 21 May 2004, nardelli wrote:

> The api for usb_control_msg says, 'If successful, it returns 0, othwise a
> negative error number', and I didn't see any other way to figure out how
> much data was being returned.

In the current kernel sources, the kerneldoc for usb_control_msg() says
"If successful, it returns the number of bytes transferred, otherwise a 
negative error number."

Alan Stern


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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 14:48   ` nardelli
  2004-05-21 15:05     ` Alan Stern
@ 2004-05-21 15:41     ` Greg KH
  1 sibling, 0 replies; 26+ messages in thread
From: Greg KH @ 2004-05-21 15:41 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Fri, May 21, 2004 at 10:48:54AM -0400, nardelli wrote:
> 
> The old check would error out of visor_open() with -ENODEV if there was
> not a read_urb for any device, and there was a comment that this was
> needed for 'some brain dead Sony devices'.  I modified this to error out
> only for Sony devices, instead of just a comment about them.  This
> should not modify the behavior on Sonys, but may on others (namely treos).
> 
> I'd really like to know more about why some Sony devices do not have a
> read_urb, but at least for now, I did not change functionality for them.

The problem is that the "bad" Sony devices return that they have 2 ports
available, however their endpoints do not reflect this.  So I check for
a read urb to test if this really is a valid port or not.

Hm, now that I can modify the number of ports on the fly, we should just
catch this in the initialization of the device which would solve this
problem the "right way".

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 15:05     ` Alan Stern
@ 2004-05-21 17:08       ` nardelli
  0 siblings, 0 replies; 26+ messages in thread
From: nardelli @ 2004-05-21 17:08 UTC (permalink / raw)
  To: Alan Stern; +Cc: Greg KH, linux-kernel, linux-usb-devel

Alan Stern wrote:
> On Fri, 21 May 2004, nardelli wrote:
> 
> 
>>The api for usb_control_msg says, 'If successful, it returns 0, othwise a
>>negative error number', and I didn't see any other way to figure out how
>>much data was being returned.
> 
> 
> In the current kernel sources, the kerneldoc for usb_control_msg() says
> "If successful, it returns the number of bytes transferred, otherwise a 
> negative error number."
> 

Sorry, I was looking at dated api docs at kernelnewbies.org.  I'll use
the size returned from usb_control_msg() instead of memset().


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21  4:30 ` [linux-usb-devel] " Greg KH
  2004-05-21  5:03   ` Pete Zaitcev
  2004-05-21 14:48   ` nardelli
@ 2004-05-21 19:51   ` nardelli
  2004-05-21 20:01     ` jkroon
  2004-05-21 20:44     ` Greg KH
  2 siblings, 2 replies; 26+ messages in thread
From: nardelli @ 2004-05-21 19:51 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

I've made all of the changes that recommended below.  If it looks like
I've missed anything, please indicate so.



--- linux-2.6.6.old/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
+++ linux-2.6.6.new/drivers/usb/serial/visor.c	2004-05-21 15:02:30.938875280 -0400
@@ -398,7 +398,8 @@ static int visor_open (struct usb_serial
 	
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->read_urb) {
+	if (serial->dev->descriptor.idVendor == SONY_VENDOR_ID &&
+			!port->read_urb) {
 		/* this is needed for some brain dead Sony devices */
 		dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
 		return -ENODEV;
@@ -416,17 +417,20 @@ static int visor_open (struct usb_serial
 		port->tty->low_latency = 1;
 
 	/* Start reading from the device */
-	usb_fill_bulk_urb (port->read_urb, serial->dev,
-			   usb_rcvbulkpipe (serial->dev, 
-					    port->bulk_in_endpointAddress),
-			   port->read_urb->transfer_buffer,
-			   port->read_urb->transfer_buffer_length,
-			   visor_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result) {
-		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n",
-			__FUNCTION__, result);
-		goto exit;
+	if (port->read_urb) {
+		usb_fill_bulk_urb (port->read_urb, serial->dev,
+			usb_rcvbulkpipe (serial->dev, 
+				port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			visor_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+		if (result) {
+			dev_err(&port->dev,
+				"%s - failed submitting read urb, error %d\n",
+				__FUNCTION__, result);
+			goto exit;
+		}
 	}
 	
 	if (port->interrupt_in_urb) {
@@ -456,7 +460,8 @@ static void visor_close (struct usb_seri
 		return;
 	
 	/* shutdown our urbs */
-	usb_unlink_urb (port->read_urb);
+	if (port->read_urb)
+		usb_unlink_urb (port->read_urb);
 	if (port->interrupt_in_urb)
 		usb_unlink_urb (port->interrupt_in_urb);
 
@@ -622,15 +627,20 @@ static void visor_read_bulk_callback (st
 	bytes_in += urb->actual_length;
 
 	/* Continue trying to always read  */
-	usb_fill_bulk_urb (port->read_urb, serial->dev,
-			   usb_rcvbulkpipe (serial->dev,
-					    port->bulk_in_endpointAddress),
-			   port->read_urb->transfer_buffer,
-			   port->read_urb->transfer_buffer_length,
-			   visor_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+	if (port->read_urb) {
+		usb_fill_bulk_urb (port->read_urb, serial->dev,
+				usb_rcvbulkpipe (serial->dev,
+				port->bulk_in_endpointAddress),
+				port->read_urb->transfer_buffer,
+				port->read_urb->transfer_buffer_length,
+				visor_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+		if (result)
+			dev_err(&port->dev,
+				"%s - failed resubmitting read urb, error %d\n",
+				__FUNCTION__, result);
+	}
+  
 	return;
 }
 
@@ -675,7 +685,9 @@ exit:
 static void visor_throttle (struct usb_serial_port *port)
 {
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	usb_unlink_urb (port->read_urb);
+	if (port->read_urb) {
+		usb_unlink_urb (port->read_urb);
+	}
 }
 
 
@@ -685,10 +697,14 @@ static void visor_unthrottle (struct usb
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+	if (port->read_urb) {
+		port->read_urb->dev = port->serial->dev;
+		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+		if (result)
+			dev_err(&port->dev,
+				"%s - failed submitting read urb, error %d\n",
+				__FUNCTION__, result);
+	}
 }
 
 static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id)
@@ -721,41 +737,55 @@ static int palm_os_3_probe (struct usb_s
 			__FUNCTION__, retval);
 		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;
-	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
-		connection_info->num_ports);
-
-	for (i = 0; i < num_ports; ++i) {
-		switch (connection_info->connections[i].port_function_id) {
-			case VISOR_FUNCTION_GENERIC:
-				string = "Generic";
-				break;
-			case VISOR_FUNCTION_DEBUGGER:
-				string = "Debugger";
-				break;
-			case VISOR_FUNCTION_HOTSYNC:
-				string = "HotSync";
-				break;
-			case VISOR_FUNCTION_CONSOLE:
-				string = "Console";
-				break;
-			case VISOR_FUNCTION_REMOTE_FILE_SYS:
-				string = "Remote File System";
-				break;
-			default:
-				string = "unknown";
-				break;	
+	else if (retval != sizeof(*connection_info)) {
+		/* real invalid connection info handling is below */
+		num_ports = 0;
+	}
+	else {
+	        connection_info = (struct visor_connection_info *)
+			transfer_buffer;
+
+		le16_to_cpus(&connection_info->num_ports);
+		num_ports = connection_info->num_ports;
+
+		for (i = 0; i < num_ports; ++i) {
+			switch (connection_info->connections[i].
+					port_function_id) {
+				case VISOR_FUNCTION_GENERIC:
+					string = "Generic";
+					break;
+				case VISOR_FUNCTION_DEBUGGER:
+					string = "Debugger";
+					break;
+				case VISOR_FUNCTION_HOTSYNC:
+					string = "HotSync";
+					break;
+				case VISOR_FUNCTION_CONSOLE:
+					string = "Console";
+					break;
+				case VISOR_FUNCTION_REMOTE_FILE_SYS:
+					string = "Remote File System";
+					break;
+				default:
+					string = "unknown";
+					break;
+			}
+			dev_info(dev, "%s: port %d, is for %s use\n",
+				serial->type->name, connection_info->
+				connections[i].port, string);
 		}
-		dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
-			 connection_info->connections[i].port, string);
 	}
+	/*
+	* Handle devices that report invalid stuff here.
+	*/
+	if (num_ports == 0 || num_ports > 2) {
+		dev_warn (dev, "%s: No valid connect info available\n",
+			serial->type->name);
+		num_ports = 2;
+	}
+  
+	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+		num_ports);
 
 	/*
 	 * save off our num_ports info so that we can use it in the
@@ -887,8 +917,7 @@ static int clie_3_5_startup (struct usb_
  
 static int treo_attach (struct usb_serial *serial)
 {
-	struct usb_serial_port *port;
-	int i;
+	struct usb_serial_port swap_port;
 
 	/* Only do this endpoint hack for the Handspring devices with
 	 * interrupt in endpoints, which for now are the Treo devices. */
@@ -898,31 +927,40 @@ static int treo_attach (struct usb_seria
 
 	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;
-	}
+	/*
+	* It appears that Treos want to use the 1st interrupt endpoint to
+	* communicate with the 2nd bulk out endpoint, so let's swap the 1st
+	* and 2nd bulk in and interrupt endpoints.  Note that swapping the
+	* bulk out endpoints would break lots of apps that want to communicate
+	* on the second port.
+	*/
+	swap_port.read_urb = serial->port[0]->read_urb;
+	swap_port.bulk_in_endpointAddress = serial->port[0]->
+		bulk_in_endpointAddress;
+	swap_port.bulk_in_buffer = serial->port[0]->bulk_in_buffer;
+	swap_port.interrupt_in_urb = serial->port[0]->interrupt_in_urb;
+	swap_port.interrupt_in_endpointAddress = serial->port[0]->
+		interrupt_in_endpointAddress;
+	swap_port.interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
+ 
+	serial->port[0]->read_urb = serial->port[1]->read_urb;
+	serial->port[0]->bulk_in_endpointAddress = serial->port[1]->
+		bulk_in_endpointAddress;
+	serial->port[0]->bulk_in_buffer = serial->port[1]->bulk_in_buffer;
+	serial->port[0]->interrupt_in_urb = serial->port[1]->interrupt_in_urb;
+	serial->port[0]->interrupt_in_endpointAddress = serial->port[1]->
+		interrupt_in_endpointAddress;
+	serial->port[0]->interrupt_in_buffer = serial->port[1]->
+		interrupt_in_buffer;
+
+	serial->port[1]->read_urb = swap_port.read_urb;
+	serial->port[1]->bulk_in_endpointAddress = swap_port.
+		bulk_in_endpointAddress;
+	serial->port[1]->bulk_in_buffer = swap_port.bulk_in_buffer;
+	serial->port[1]->interrupt_in_urb = swap_port.interrupt_in_urb;
+	serial->port[1]->interrupt_in_endpointAddress = swap_port.
+		interrupt_in_endpointAddress;
+	serial->port[1]->interrupt_in_buffer = swap_port.interrupt_in_buffer;
 
 	return 0;
 }




Greg KH wrote:
> On Thu, May 20, 2004 at 07:08:56PM -0400, nardelli wrote:
> 
>>Here is a proposed patch for Oops on disconnect in the visor module.
>>For details of the problem, please see
>>http://bugzilla.kernel.org/show_bug.cgi?id=2289
>>
>>I would really appreciate it if anyone that uses this module could please
>>try this patch to make sure that it works as intended.  Also, as this is
>>the first patch that I've submitted, please feel free to be brutally
>>honest regarding content, formatting, etc.
> 
> 
> Ok, I'll be brutal, but remember, you asked :)
> 
> First off, read Documentation/SubmittingPatches and
> Documentation/CodingStyle to see the proper way to make patches, and how
> to format the code.
> 
> 
>>--- old/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
>>+++ new/linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400
> 
> 
> I need to be able to apply this patch by using a -p1 in the kernel
> directory.  So the patch should be one directory up and look like:
> 
> --- linux-2.6.6/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
> +++ linux-2.6.6/drivers/usb/serial/visor.c	2004-05-20 18:04:24.000000000 -0400
> 
> 
> 
>>@@ -12,6 +12,13 @@
>>  *
>>  * See Documentation/usb/usb-serial.txt for more information on using this driver
>>  *
>>+ * (5/20/2004) Joe Nardelli
>>+ *	Reduced possibility for unitialized data access in palm_os_3_probe.
>>+ *	Modified workaround for treo endpoint setup in treo_attach.
>>+ *	Removed assumptions that port->read_urb was always valid (is not true
>>+ *	for usb serial devices with more bulk out or interrupt endpoints than
>>+ *	bulk in endpoints).
> 
> 
> I'm trying not to add new stuff to the changelog at the beginning of the
> file, but this is not really a big deal.
> 
> 
>>-	if (!port->read_urb) {
>>+	if ((serial->dev->descriptor.idVendor != SONY_VENDOR_ID && !port->read_urb))
>>+	{
> 
> 
> Wrong formatting style for the '{'
> 
> Your patch says that we might not have a read_urb for the given port?
> How could that be true?  The check here in open() will catch any devices
> that this might not be correct for.  So that portion of this patch is
> not needed, right?
> 
> 
>> static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id)
>>@@ -710,6 +728,13 @@
>> 		return -ENOMEM;
>> 	}
>> 
>>+	/*
>>+	* We don't know how much data gets written into transfer_buffer, so let's
>>+	* at least set it all to 0 to avoid putting random data into num_ports
>>+	* (which causes unitialized, and possibly unallocated data to be accessed)
>>+	*/
>>+	memset (transfer_buffer, 0, sizeof(*connection_info));
> 
> 
> Um, we ask for a set ammount of data, and we should get it.  But we
> should check the size of the data returned to make sure of this, right?
> 
> 
>> 	/* send a get connection info request */
>> 	retval = usb_control_msg (serial->dev,
>> 				  usb_rcvctrlpipe(serial->dev, 0),
>>@@ -726,11 +751,20 @@
>> 
>> 	le16_to_cpus(&connection_info->num_ports);
>> 	num_ports = connection_info->num_ports;
>>-	/* handle devices that report invalid stuff here */
>>-	if (num_ports > 2)
>>+	/*
>>+	* Handle devices that report invalid stuff here.  I think that this will
>>+	* work for both big and little endian architectures that do not report
>>+	* back valid connect info, but I'd still like to verify this on a big
>>+	* endian machine.  Any testers?
>>+	*/
> 
> 
> The call above to le16_to_cpus() will handle the endian issue here.
> This comment can be removed.
> 
> 
>>+	if (num_ports <= 0 || num_ports > 2) {
> 
> 
> I like the idea of this check, but you are trying to test for a negative
> value on a __u16 variable, which is always unsigned.  So that check will
> never be true :)
> 
> 
>>+		dev_warn (dev, "%s: No valid connect info available\n",
>>+			serial->type->name);
>> 		num_ports = 2;
>>+	}
>>+  
>> 	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
>>-		connection_info->num_ports);
>>+		num_ports);
>> 
>> 	for (i = 0; i < num_ports; ++i) {
>> 		switch (connection_info->connections[i].port_function_id) {
>>@@ -887,8 +921,7 @@
>>  
>> static int treo_attach (struct usb_serial *serial)
>> {
>>-	struct usb_serial_port *port;
>>-	int i;
>>+	struct usb_serial_port swap_port;
>> 
>> 	/* Only do this endpoint hack for the Handspring devices with
>> 	 * interrupt in endpoints, which for now are the Treo devices. */
>>@@ -898,31 +931,32 @@
>> 
>> 	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;
>>-	}
>>+	/*
>>+	* It appears that Treos want to use the 1st interrupt endpoint to communicate
>>+	* with the 2nd bulk out endpoint, so let's swap the 1st and 2nd bulk in
>>+	* and interrupt endpoints.  Note that swapping the bulk out endpoints would
>>+	* break lots of apps that want to communicate on the second port.
>>+	*/
>>+	swap_port.read_urb = serial->port[0]->read_urb;
>>+	swap_port.bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
>>+	swap_port.bulk_in_buffer = serial->port[0]->bulk_in_buffer;
>>+	swap_port.interrupt_in_urb = serial->port[0]->interrupt_in_urb;
>>+	swap_port.interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
>>+	swap_port.interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
>>+ 
>>+	serial->port[0]->read_urb = serial->port[1]->read_urb;
>>+	serial->port[0]->bulk_in_endpointAddress = serial->port[1]->bulk_in_endpointAddress;
>>+	serial->port[0]->bulk_in_buffer = serial->port[1]->bulk_in_buffer;
>>+	serial->port[0]->interrupt_in_urb = serial->port[1]->interrupt_in_urb;
>>+	serial->port[0]->interrupt_in_endpointAddress = serial->port[1]->interrupt_in_endpointAddress;
>>+	serial->port[0]->interrupt_in_buffer = serial->port[1]->interrupt_in_buffer;
>>+
>>+	serial->port[1]->read_urb = swap_port.read_urb;
>>+	serial->port[1]->bulk_in_endpointAddress = swap_port.bulk_in_endpointAddress;
>>+	serial->port[1]->bulk_in_buffer = swap_port.bulk_in_buffer;
>>+	serial->port[1]->interrupt_in_urb = swap_port.interrupt_in_urb;
>>+	serial->port[1]->interrupt_in_endpointAddress = swap_port.interrupt_in_endpointAddress;
>>+	serial->port[1]->interrupt_in_buffer = swap_port.interrupt_in_buffer;
> 
> 
> Now this is the meat of the patch.  Is that all that is needed, just
> swaping the info?  That makes more sense than the hack of assigning the
> same port data to both ports.  Does this work properly on disconnect
> too?
> 
> Thanks a lot for doing this, with some cleanups I'll be glad to accept
> this patch.
> 
> thanks,
> 
> greg k-h
> 
> 
> -------------------------------------------------------
> This SF.Net email is sponsored by: Oracle 10g
> Get certified on the hottest thing ever to hit the market... Oracle 10g. 
> Take an Oracle 10g class now, and we'll give you the exam FREE.
> http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click
> _______________________________________________
> linux-usb-devel@lists.sourceforge.net
> To unsubscribe, use the last form field at:
> https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
> 


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 19:51   ` nardelli
@ 2004-05-21 20:01     ` jkroon
  2004-05-21 20:22       ` nardelli
  2004-05-21 20:44     ` Greg KH
  1 sibling, 1 reply; 26+ messages in thread
From: jkroon @ 2004-05-21 20:01 UTC (permalink / raw)
  To: nardelli; +Cc: Greg KH, linux-kernel, linux-usb-devel

> I've made all of the changes that recommended below.  If it looks like
> I've missed anything, please indicate so.
>
>

[snip]

>>
>>>+	if (num_ports <= 0 || num_ports > 2) {
>>
>>
>> I like the idea of this check, but you are trying to test for a negative
>> value on a __u16 variable, which is always unsigned.  So that check will
>> never be true :)

What happens if num_ports == 0?  Not that hardware should ever report that.

[snip]


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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 20:01     ` jkroon
@ 2004-05-21 20:22       ` nardelli
  0 siblings, 0 replies; 26+ messages in thread
From: nardelli @ 2004-05-21 20:22 UTC (permalink / raw)
  To: jkroon; +Cc: Greg KH, linux-kernel, linux-usb-devel

jkroon@cs.up.ac.za wrote:
>>I've made all of the changes that recommended below.  If it looks like
>>I've missed anything, please indicate so.
>>
>>
> 
> 
> [snip]
> 
> 
>>>>+	if (num_ports <= 0 || num_ports > 2) {
>>>
>>>
>>>I like the idea of this check, but you are trying to test for a negative
>>>value on a __u16 variable, which is always unsigned.  So that check will
>>>never be true :)
> 
> 
> What happens if num_ports == 0?  Not that hardware should ever report that.
> 
> [snip]
> 
> 

Short answer:
A warning is logged and num_ports defaults to 2.

Long answer:

Unfortunately, it does not apear that this class of device sends any kind of
connect info back in repsonse to VISOR_GET_CONNECTION_INFORMATION,
PALM_GET_EXT_CONNECTION_INFORMATION, or for that matter any request under
200 (or some similiar number - I don't remember how far I tested).

Based upon a usb packet capture under windoze, I believe that the device
is not capable of this.  I'd really like some kind of documentation on
the connection protocol, but I've come up completely empty handed in that
regard.

The packet capture available at
http://bugzilla.kernel.org/attachment.cgi?id=2924&action=view shows the
attempt to send both VISOR_GET_CONNECTION_INFORMATION (3) and 
PALM_GET_EXT_CONNECTION_INFORMATION (4) requests.  Both times nothing is
returned.

In any case, when no valid connection info is found, num_ports is initially
set to 0, a warning is logged, and num_ports defaults to 2.


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 19:51   ` nardelli
  2004-05-21 20:01     ` jkroon
@ 2004-05-21 20:44     ` Greg KH
  2004-05-21 21:44       ` nardelli
  1 sibling, 1 reply; 26+ messages in thread
From: Greg KH @ 2004-05-21 20:44 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Fri, May 21, 2004 at 03:51:23PM -0400, nardelli wrote:
> I've made all of the changes that recommended below.  If it looks like
> I've missed anything, please indicate so.
> 
> 
> 
> --- linux-2.6.6.old/drivers/usb/serial/visor.c	2004-05-09 
> 22:32:27.000000000 -0400
> +++ linux-2.6.6.new/drivers/usb/serial/visor.c	2004-05-21 
> 15:02:30.938875280 -0400

Patch is line-wrapped, so I can't apply it :(

> @@ -456,7 +460,8 @@ static void visor_close (struct usb_seri
> 		return;
> 	
> 	/* shutdown our urbs */
> -	usb_unlink_urb (port->read_urb);
> +	if (port->read_urb)
> +		usb_unlink_urb (port->read_urb);

I really do not think these extra checks for read_urb all of the place
need to be added.  We take care of it in the open() call, right?


> 	if (port->interrupt_in_urb)
> 		usb_unlink_urb (port->interrupt_in_urb);
> 
> @@ -622,15 +627,20 @@ static void visor_read_bulk_callback (st
> 	bytes_in += urb->actual_length;
> 
> 	/* Continue trying to always read  */
> -	usb_fill_bulk_urb (port->read_urb, serial->dev,
> -			   usb_rcvbulkpipe (serial->dev,
> -					    port->bulk_in_endpointAddress),
> -			   port->read_urb->transfer_buffer,
> -			   port->read_urb->transfer_buffer_length,
> -			   visor_read_bulk_callback, port);
> -	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
> -	if (result)
> -		dev_err(&port->dev, "%s - failed resubmitting read urb, 
> error %d\n", __FUNCTION__, result);
> +	if (port->read_urb) {
> +		usb_fill_bulk_urb (port->read_urb, serial->dev,
> +				usb_rcvbulkpipe (serial->dev,
> +				port->bulk_in_endpointAddress),
> +				port->read_urb->transfer_buffer,
> +				port->read_urb->transfer_buffer_length,
> +				visor_read_bulk_callback, port);
> +		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
> +		if (result)
> +			dev_err(&port->dev,
> +				"%s - failed resubmitting read urb, error 
> %d\n",
> +				__FUNCTION__, result);
> +	}
> +  
> 	return;
> }
> 
> @@ -675,7 +685,9 @@ exit:
> static void visor_throttle (struct usb_serial_port *port)
> {
> 	dbg("%s - port %d", __FUNCTION__, port->number);
> -	usb_unlink_urb (port->read_urb);
> +	if (port->read_urb) {
> +		usb_unlink_urb (port->read_urb);
> +	}
> }
> 
> 
> @@ -685,10 +697,14 @@ static void visor_unthrottle (struct usb
> 
> 	dbg("%s - port %d", __FUNCTION__, port->number);
> 
> -	port->read_urb->dev = port->serial->dev;
> -	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
> -	if (result)
> -		dev_err(&port->dev, "%s - failed submitting read urb, error 
> %d\n", __FUNCTION__, result);
> +	if (port->read_urb) {
> +		port->read_urb->dev = port->serial->dev;
> +		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
> +		if (result)
> +			dev_err(&port->dev,
> +				"%s - failed submitting read urb, error 
> %d\n",
> +				__FUNCTION__, result);
> +	}
> }
> 
> static int palm_os_3_probe (struct usb_serial *serial, const struct 
> usb_device_id *id)
> @@ -721,41 +737,55 @@ static int palm_os_3_probe (struct usb_s
> 			__FUNCTION__, retval);
> 		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;
> -	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
> -		connection_info->num_ports);
> -
> -	for (i = 0; i < num_ports; ++i) {
> -		switch (connection_info->connections[i].port_function_id) {
> -			case VISOR_FUNCTION_GENERIC:
> -				string = "Generic";
> -				break;
> -			case VISOR_FUNCTION_DEBUGGER:
> -				string = "Debugger";
> -				break;
> -			case VISOR_FUNCTION_HOTSYNC:
> -				string = "HotSync";
> -				break;
> -			case VISOR_FUNCTION_CONSOLE:
> -				string = "Console";
> -				break;
> -			case VISOR_FUNCTION_REMOTE_FILE_SYS:
> -				string = "Remote File System";
> -				break;
> -			default:
> -				string = "unknown";
> -				break;	
> +	else if (retval != sizeof(*connection_info)) {
> +		/* real invalid connection info handling is below */
> +		num_ports = 0;
> +	}

Change this to a "if" instead of a "else if".
Actually just set num_ports to 0 at the beginning of the function, and
then just check for a valud retval and do the code below...

> +	else {
> +	        connection_info = (struct visor_connection_info *)
> +			transfer_buffer;

<snip>

Also, don't quote the whole previous message, that's not nice...

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 20:44     ` Greg KH
@ 2004-05-21 21:44       ` nardelli
  2004-05-21 21:56         ` Greg KH
  2004-05-21 22:04         ` nardelli
  0 siblings, 2 replies; 26+ messages in thread
From: nardelli @ 2004-05-21 21:44 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> On Fri, May 21, 2004 at 03:51:23PM -0400, nardelli wrote:
> 
> 
> Patch is line-wrapped, so I can't apply it :(
> 
> 

Hmmm... I couldn't see the linewrap in the original I sent, or
in test ones that I did.  Probably my mail tool, but then it
is getting late on a Friday, which probably means that it is me.

To aid in diagnosing where I'm goofing up, could you point out
a spot where it is linewrapping?


>>@@ -456,7 +460,8 @@ static void visor_close (struct usb_seri
>>		return;
>>	
>>	/* shutdown our urbs */
>>-	usb_unlink_urb (port->read_urb);
>>+	if (port->read_urb)
>>+		usb_unlink_urb (port->read_urb);
> 
> 
> I really do not think these extra checks for read_urb all of the place
> need to be added.  We take care of it in the open() call, right?
> 
> 
> 

Yes - less clutter and more efficient too.

>>+	else if (retval != sizeof(*connection_info)) {
>>+		/* real invalid connection info handling is below */
>>+		num_ports = 0;
>>+	}
> 
> 
> Change this to a "if" instead of a "else if".
> Actually just set num_ports to 0 at the beginning of the function, and
> then just check for a valud retval and do the code below...
> 
> 

Yep - same comment as above.

>>+	else {
>>+	        connection_info = (struct visor_connection_info *)
>>+			transfer_buffer;
> 
> 
> 
> greg k-h
> 


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 21:44       ` nardelli
@ 2004-05-21 21:56         ` Greg KH
  2004-05-21 22:04         ` nardelli
  1 sibling, 0 replies; 26+ messages in thread
From: Greg KH @ 2004-05-21 21:56 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Fri, May 21, 2004 at 05:44:09PM -0400, nardelli wrote:
> Greg KH wrote:
> >On Fri, May 21, 2004 at 03:51:23PM -0400, nardelli wrote:
> >
> >
> >Patch is line-wrapped, so I can't apply it :(
> >
> >
> 
> Hmmm... I couldn't see the linewrap in the original I sent, or
> in test ones that I did.  Probably my mail tool, but then it
> is getting late on a Friday, which probably means that it is me.
> 
> To aid in diagnosing where I'm goofing up, could you point out
> a spot where it is linewrapping?

Ok, my bad, sorry, mutt likes to wrap stuff when the mail has the
following header in it like yours did:
	Content-Type: text/plain; charset=us-ascii; format=flowed

Sorry about that, the patch is not wrapped.

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 21:44       ` nardelli
  2004-05-21 21:56         ` Greg KH
@ 2004-05-21 22:04         ` nardelli
  2004-05-21 22:30           ` Greg KH
  1 sibling, 1 reply; 26+ messages in thread
From: nardelli @ 2004-05-21 22:04 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

nardelli wrote:
> Greg KH wrote:
> 
> 
>>> @@ -456,7 +460,8 @@ static void visor_close (struct usb_seri
>>>         return;
>>>     
>>>     /* shutdown our urbs */
>>> -    usb_unlink_urb (port->read_urb);
>>> +    if (port->read_urb)
>>> +        usb_unlink_urb (port->read_urb);
>>
>>
>> I really do not think these extra checks for read_urb all of the place
>> need to be added.  We take care of it in the open() call, right?
>>
> 
> Yes - less clutter and more efficient too.
> 


Maybe I spoke too soon here.  We have 1 bulk in, 2 bulk out, and 1 interrupt
in endpoint, which by the logic in usb-serial, translates to 2 ports.  Only
one of those ports can have a read_urb associated with it, unless we want to
do some really fancy juggling.  This means that we're going to have a port
that does not have a valid read_urb associated with it, even after open().
In this case, any attempt to read from /dev/ttyUSB0 (even if it is useless)
would result in a null pointer access violation unless there is some
form of protection around it.  Not permitting reads on this port would get
around this, but putting 'if' checks around access to read_urb is probably
much simpler.

I'm at a loss why this device has an uneven number of bulk in and bulk out
endpoints.

Any thoughts?

-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 22:04         ` nardelli
@ 2004-05-21 22:30           ` Greg KH
  2004-05-24 17:20             ` nardelli
  0 siblings, 1 reply; 26+ messages in thread
From: Greg KH @ 2004-05-21 22:30 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Fri, May 21, 2004 at 06:04:46PM -0400, nardelli wrote:
> 
> Maybe I spoke too soon here.  We have 1 bulk in, 2 bulk out, and 1 interrupt
> in endpoint, which by the logic in usb-serial, translates to 2 ports.  Only
> one of those ports can have a read_urb associated with it, unless we want to
> do some really fancy juggling.  This means that we're going to have a port
> that does not have a valid read_urb associated with it, even after open().

But the call to open() fails, which prevents any of the other tty calls
from happening on that port.  That's why we don't need to make that
check anywhere else.

> I'm at a loss why this device has an uneven number of bulk in and bulk out
> endpoints.

Stupid hardware engineers?  Who really knows...

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-21 22:30           ` Greg KH
@ 2004-05-24 17:20             ` nardelli
  2004-05-24 19:38               ` nardelli
  2004-05-24 20:08               ` Greg KH
  0 siblings, 2 replies; 26+ messages in thread
From: nardelli @ 2004-05-24 17:20 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> On Fri, May 21, 2004 at 06:04:46PM -0400, nardelli wrote:
> 
>>Maybe I spoke too soon here.  We have 1 bulk in, 2 bulk out, and 1 interrupt
>>in endpoint, which by the logic in usb-serial, translates to 2 ports.  Only
>>one of those ports can have a read_urb associated with it, unless we want to
>>do some really fancy juggling.  This means that we're going to have a port
>>that does not have a valid read_urb associated with it, even after open().
> 
> 
> But the call to open() fails, which prevents any of the other tty calls
> from happening on that port.  That's why we don't need to make that
> check anywhere else.
> 
> 

The call to open() does not fail - with only a write_urb associated with it,
it's not a very interesting port, but data can be written to it, at least in
small quantities (see below).  The first patch that I submitted had a bug
(which I've fixed) in it 
http://marc.theaimsgroup.com/?l=linux-usb-devel&m=108515267617337&w=2
that Pete Zaitcev pointed out in visor_open() that might be confusing the 
issue.

The behavior that I intended was to allow devices that have more bulk out
endpoints than bulk in endpoints (namely treos) to still use the write only
port.  Mainly though, it was to allow for swapping endpoints to allow for
the uneven number of in and out endpoints.  This was not a problem prior to
now since the endpoints were being copied instead of swapped.


>>I'm at a loss why this device has an uneven number of bulk in and bulk out
>>endpoints.
> 
> 
> Stupid hardware engineers?  Who really knows...
> 

I bet someone really smart will figure it out - it probably just melts the ROM,
or something else useful :-)


One more question - my system does not really like it when I redirect /dev/urandom
to either the first or second port.  I know that it obviosuly makes no sense to
do such a thing, but is it expected that there should be no problems associated
with this.  I'm not finished testing, so I'm not sure how severe a problem develops.
I'll report in when I know more about this.


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 17:20             ` nardelli
@ 2004-05-24 19:38               ` nardelli
  2004-05-24 20:06                 ` Greg KH
  2004-05-24 20:08               ` Greg KH
  1 sibling, 1 reply; 26+ messages in thread
From: nardelli @ 2004-05-24 19:38 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

nardelli wrote:
> 
> One more question - my system does not really like it when I redirect /dev/urandom
> to either the first or second port.  I know that it obviosuly makes no sense to
> do such a thing, but is it expected that there should be no problems associated
> with this.  I'm not finished testing, so I'm not sure how severe a problem develops.
> I'll report in when I know more about this.
> 

Here's some preliminary info:

1) Whether writing to the 1st or 2nd port, the machine hangs pretty badly
after catting /dev/urandom for more than 1 second or two.  This continues
even after catting has stopped, and the device has been disconnected.  This
smells like some type of resource leak, probably memory, to me.

2) I've included an Oops when writing to the 1st serial port, showing some
difficulty allocating memory.

3) After looking at visor_write(), I was a bit surprised to see it
allocating its own urb and buffer, while I thought it would be using
the ones that were allocated in usb-serial.usb_serial_probe().  After
looking at other serial devices that use usb_submit_urb() in their
write() functions, I found that the following used the buffers/urb
allocated for them:

cyberjack, digi_acceleport, generic, io_ti, ipaq, ir-usb, keyspan_pda,
kobil_sct, mct_u232, omninet, pl2303, safe_serial

while I found that the following created their own (some for each write):

empeg, ftdi_sio, keyspan, kl5kusb105, visor, whiteheat

I'm not so sure about:
io_edgeport


Is this expected behavior, or am I just missing something here?

It would seem like reusing the buffer and urb would be advantageous,
but there may be more issues here than I am aware of.



May 24 13:54:44 iscjoe kernel: cat: page allocation failure. order:0, mode:0x20
May 24 13:54:44 iscjoe kernel: Call Trace:
May 24 13:54:44 iscjoe kernel:  [__alloc_pages+850/852] __alloc_pages+0x352/0x354
May 24 13:54:44 iscjoe kernel:  [<c013e36e>] __alloc_pages+0x352/0x354
May 24 13:54:44 iscjoe kernel:  [__get_free_pages+34/63] __get_free_pages+0x22/0x3f
May 24 13:54:44 iscjoe kernel:  [<c013e392>] __get_free_pages+0x22/0x3f
May 24 13:54:44 iscjoe kernel:  [dma_alloc_coherent+77/131] dma_alloc_coherent+0x4d/0x83
May 24 13:54:44 iscjoe kernel:  [<c010c43d>] dma_alloc_coherent+0x4d/0x83
May 24 13:54:44 iscjoe kernel:  [pool_alloc_page+92/207] pool_alloc_page+0x5c/0xcf
May 24 13:54:44 iscjoe kernel:  [<c025fba8>] pool_alloc_page+0x5c/0xcf
May 24 13:54:44 iscjoe kernel:  [dma_pool_alloc+261/445] dma_pool_alloc+0x105/0x1bd
May 24 13:54:44 iscjoe kernel:  [<c025fed9>] dma_pool_alloc+0x105/0x1bd
May 24 13:54:44 iscjoe kernel:  [get_device+26/33] get_device+0x1a/0x21
May 24 13:54:44 iscjoe kernel:  [<c025cc33>] get_device+0x1a/0x21
May 24 13:54:44 iscjoe kernel:  [uhci_append_queued_urb+178/276] uhci_append_queued_urb+0xb2/0x114
May 24 13:54:44 iscjoe kernel:  [<c02dadba>] uhci_append_queued_urb+0xb2/0x114
May 24 13:54:44 iscjoe kernel:  [uhci_alloc_td+43/124] uhci_alloc_td+0x2b/0x7c
May 24 13:54:44 iscjoe kernel:  [<c02da70c>] uhci_alloc_td+0x2b/0x7c
May 24 13:54:44 iscjoe kernel:  [uhci_submit_common+360/762] uhci_submit_common+0x168/0x2fa
May 24 13:54:44 iscjoe kernel:  [<c02db8ac>] uhci_submit_common+0x168/0x2fa
May 24 13:54:44 iscjoe kernel:  [uhci_urb_enqueue+469/731] uhci_urb_enqueue+0x1d5/0x2db
May 24 13:54:44 iscjoe kernel:  [<c02dc09d>] uhci_urb_enqueue+0x1d5/0x2db
May 24 13:54:44 iscjoe kernel:  [get_device+26/33] get_device+0x1a/0x21
May 24 13:54:44 iscjoe kernel:  [<c025cc33>] get_device+0x1a/0x21
May 24 13:54:44 iscjoe kernel:  [hcd_submit_urb+287/370] hcd_submit_urb+0x11f/0x172
May 24 13:54:44 iscjoe kernel:  [<c02c8bf4>] hcd_submit_urb+0x11f/0x172
May 24 13:54:44 iscjoe kernel:  [usb_submit_urb+602/844] usb_submit_urb+0x25a/0x34c
May 24 13:54:44 iscjoe kernel:  [<c02c99b7>] usb_submit_urb+0x25a/0x34c
May 24 13:54:44 iscjoe kernel:  [__kmalloc+436/611] __kmalloc+0x1b4/0x263
May 24 13:54:44 iscjoe kernel:  [<c01439dd>] __kmalloc+0x1b4/0x263
May 24 13:54:44 iscjoe kernel:  [pg0+273019921/1068740608] visor_write+0xdf/0x25a [visor]
May 24 13:54:44 iscjoe kernel:  [<d0922411>] visor_write+0xdf/0x25a [visor]
May 24 13:54:44 iscjoe kernel:  [pg0+273274118/1068740608] serial_write+0x85/0x100 [usbserial]
May 24 13:54:44 iscjoe kernel:  [<d0960506>] serial_write+0x85/0x100 [usbserial]
May 24 13:54:44 iscjoe kernel:  [tty_default_put_char+50/52] tty_default_put_char+0x32/0x34
May 24 13:54:44 iscjoe kernel:  [<c0230c4d>] tty_default_put_char+0x32/0x34
May 24 13:54:44 iscjoe kernel:  [opost+170/469] opost+0xaa/0x1d5
May 24 13:54:44 iscjoe kernel:  [<c0231486>] opost+0xaa/0x1d5
May 24 13:54:44 iscjoe kernel:  [write_chan+395/539] write_chan+0x18b/0x21b
May 24 13:54:44 iscjoe kernel:  [<c0233b4c>] write_chan+0x18b/0x21b
May 24 13:54:44 iscjoe kernel:  [default_wake_function+0/18] default_wake_function+0x0/0x12
May 24 13:54:44 iscjoe kernel:  [<c011987e>] default_wake_function+0x0/0x12
May 24 13:54:44 iscjoe kernel:  [default_wake_function+0/18] default_wake_function+0x0/0x12
May 24 13:54:44 iscjoe kernel:  [<c011987e>] default_wake_function+0x0/0x12
May 24 13:54:44 iscjoe kernel:  [tty_write+531/786] tty_write+0x213/0x312
May 24 13:54:44 iscjoe kernel:  [<c022e05e>] tty_write+0x213/0x312
May 24 13:54:44 iscjoe kernel:  [write_chan+0/539] write_chan+0x0/0x21b
May 24 13:54:44 iscjoe kernel:  [<c02339c1>] write_chan+0x0/0x21b
May 24 13:54:44 iscjoe kernel:  [tty_write+0/786] tty_write+0x0/0x312
May 24 13:54:44 iscjoe kernel:  [<c022de4b>] tty_write+0x0/0x312
May 24 13:54:44 iscjoe kernel:  [vfs_write+162/270] vfs_write+0xa2/0x10e
May 24 13:54:44 iscjoe kernel:  [<c015a4dd>] vfs_write+0xa2/0x10e
May 24 13:54:44 iscjoe kernel:  [sys_write+63/93] sys_write+0x3f/0x5d
May 24 13:54:44 iscjoe kernel:  [<c015a5e5>] sys_write+0x3f/0x5d
May 24 13:54:44 iscjoe kernel:  [sysenter_past_esp+82/113] sysenter_past_esp+0x52/0x71
May 24 13:54:44 iscjoe kernel:  [<c0105055>] sysenter_past_esp+0x52/0x71
May 24 13:54:44 iscjoe kernel:
May 24 13:54:44 iscjoe kernel: visor ttyUSB0: visor_write - usb_submit_urb(write bulk) failed with status = -12



-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 19:38               ` nardelli
@ 2004-05-24 20:06                 ` Greg KH
  2004-05-24 20:21                   ` nardelli
  2004-05-25 13:15                   ` nardelli
  0 siblings, 2 replies; 26+ messages in thread
From: Greg KH @ 2004-05-24 20:06 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Mon, May 24, 2004 at 03:38:58PM -0400, nardelli wrote:
> nardelli wrote:
> >
> >One more question - my system does not really like it when I redirect 
> >/dev/urandom
> >to either the first or second port.  I know that it obviosuly makes no 
> >sense to
> >do such a thing, but is it expected that there should be no problems 
> >associated
> >with this.  I'm not finished testing, so I'm not sure how severe a problem 
> >develops.
> >I'll report in when I know more about this.
> >
> 
> Here's some preliminary info:
> 
> 1) Whether writing to the 1st or 2nd port, the machine hangs pretty badly
> after catting /dev/urandom for more than 1 second or two.  This continues
> even after catting has stopped, and the device has been disconnected.  This
> smells like some type of resource leak, probably memory, to me.

Which machine dies?  The pilot or the Linux box?

> 2) I've included an Oops when writing to the 1st serial port, showing some
> difficulty allocating memory.

So we ran out of memory?  Not good.

> 3) After looking at visor_write(), I was a bit surprised to see it
> allocating its own urb and buffer, while I thought it would be using
> the ones that were allocated in usb-serial.usb_serial_probe().  After
> looking at other serial devices that use usb_submit_urb() in their
> write() functions, I found that the following used the buffers/urb
> allocated for them:
> 
> cyberjack, digi_acceleport, generic, io_ti, ipaq, ir-usb, keyspan_pda,
> kobil_sct, mct_u232, omninet, pl2303, safe_serial
> 
> while I found that the following created their own (some for each write):
> 
> empeg, ftdi_sio, keyspan, kl5kusb105, visor, whiteheat
> 
> I'm not so sure about:
> io_edgeport

It uses it's own buffers from what I remember.

> Is this expected behavior, or am I just missing something here?

Expected, not all of the usb-serial drivers have to do the same thing,
as they operate on very different types of hardware.

> It would seem like reusing the buffer and urb would be advantageous,
> but there may be more issues here than I am aware of.

Reusing the buffer and urb is _slow_.  The visor driver creates a new
buffer for every call to write.  It is entirely possible that you can
starve the kernel of memory by sending it the output of a raw device
node, as that data comes faster than the USB data can be sent.

But this is a different problem from the one you originally set out to
fix, how about sending a new patch for the treo disconnect problem, and
then we can work on the next issues.

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 17:20             ` nardelli
  2004-05-24 19:38               ` nardelli
@ 2004-05-24 20:08               ` Greg KH
  2004-05-24 21:42                 ` nardelli
  1 sibling, 1 reply; 26+ messages in thread
From: Greg KH @ 2004-05-24 20:08 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Mon, May 24, 2004 at 01:20:45PM -0400, nardelli wrote:
> Greg KH wrote:
> >On Fri, May 21, 2004 at 06:04:46PM -0400, nardelli wrote:
> >
> >>Maybe I spoke too soon here.  We have 1 bulk in, 2 bulk out, and 1 
> >>interrupt
> >>in endpoint, which by the logic in usb-serial, translates to 2 ports.  
> >>Only
> >>one of those ports can have a read_urb associated with it, unless we want 
> >>to
> >>do some really fancy juggling.  This means that we're going to have a port
> >>that does not have a valid read_urb associated with it, even after open().
> >
> >
> >But the call to open() fails, which prevents any of the other tty calls
> >from happening on that port.  That's why we don't need to make that
> >check anywhere else.
> >
> >
> 
> The call to open() does not fail

Today, that call does fail:

        if (!port->read_urb) {
                /* this is needed for some brain dead Sony devices */
                dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
                return -ENODEV;
        }

Let's not change that logic please.


> - with only a write_urb associated with it,
> it's not a very interesting port, but data can be written to it, at least in
> small quantities (see below).

But why?  Do you know some kind of protocol that this endpoint can
accept that is valid for the device?  If not, let's not mess with it.

thanks,

greg k-h

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 20:06                 ` Greg KH
@ 2004-05-24 20:21                   ` nardelli
  2004-05-25 13:15                   ` nardelli
  1 sibling, 0 replies; 26+ messages in thread
From: nardelli @ 2004-05-24 20:21 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> 
> But this is a different problem from the one you originally set out to
> fix, how about sending a new patch for the treo disconnect problem, and
> then we can work on the next issues.
> 

The more I look at it, the more I agree.  I just wanted to verify that I
didn't break something.


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 20:08               ` Greg KH
@ 2004-05-24 21:42                 ` nardelli
  2004-05-25 18:30                   ` Greg KH
  0 siblings, 1 reply; 26+ messages in thread
From: nardelli @ 2004-05-24 21:42 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> 
> 
> Today, that call does fail:
> 
>         if (!port->read_urb) {
>                 /* this is needed for some brain dead Sony devices */
>                 dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
>                 return -ENODEV;
>         }
> 
> Let's not change that logic please.
> 

OK.


Here's another patch.  The differences between this one and the last are:

1) Removal of extra checks to verify that port->read_urb is valid
2) Modified num_ports initialization and return value checking in palm_os_3_probe


I made this patch against 2.6.6.  Would you prefer it against 2.6.7-rc1?



--- linux-2.6.6.old/drivers/usb/serial/visor.c	2004-05-09 22:32:27.000000000 -0400
+++ linux-2.6.6.new/drivers/usb/serial/visor.c	2004-05-24 16:44:03.435277632 -0400
@@ -699,7 +699,7 @@ static int palm_os_3_probe (struct usb_s
 	char *string;
 	int retval = 0;
 	int i;
-	int num_ports;
+	int num_ports = 0;
 
 	dbg("%s", __FUNCTION__);
 
@@ -721,41 +721,52 @@ static int palm_os_3_probe (struct usb_s
 			__FUNCTION__, retval);
 		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;
-	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
-		connection_info->num_ports);
-
-	for (i = 0; i < num_ports; ++i) {
-		switch (connection_info->connections[i].port_function_id) {
-			case VISOR_FUNCTION_GENERIC:
-				string = "Generic";
-				break;
-			case VISOR_FUNCTION_DEBUGGER:
-				string = "Debugger";
-				break;
-			case VISOR_FUNCTION_HOTSYNC:
-				string = "HotSync";
-				break;
-			case VISOR_FUNCTION_CONSOLE:
-				string = "Console";
-				break;
-			case VISOR_FUNCTION_REMOTE_FILE_SYS:
-				string = "Remote File System";
-				break;
-			default:
-				string = "unknown";
-				break;	
+	if (retval == sizeof(*connection_info)) {
+	        connection_info = (struct visor_connection_info *)
+			transfer_buffer;
+
+		le16_to_cpus(&connection_info->num_ports);
+		num_ports = connection_info->num_ports;
+
+		for (i = 0; i < num_ports; ++i) {
+			switch (connection_info->connections[i].
+					port_function_id) {
+				case VISOR_FUNCTION_GENERIC:
+					string = "Generic";
+					break;
+				case VISOR_FUNCTION_DEBUGGER:
+					string = "Debugger";
+					break;
+				case VISOR_FUNCTION_HOTSYNC:
+					string = "HotSync";
+					break;
+				case VISOR_FUNCTION_CONSOLE:
+					string = "Console";
+					break;
+				case VISOR_FUNCTION_REMOTE_FILE_SYS:
+					string = "Remote File System";
+					break;
+				default:
+					string = "unknown";
+					break;
+			}
+			dev_info(dev, "%s: port %d, is for %s use\n",
+				serial->type->name, connection_info->
+				connections[i].port, string);
 		}
-		dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
-			 connection_info->connections[i].port, string);
 	}
+	/*
+	* Handle devices that report invalid stuff here.
+	*/
+	if (num_ports == 0 || num_ports > 2) {
+		dev_warn (dev, "%s: No valid connect info available\n",
+			serial->type->name);
+		num_ports = 2;
+	}
+  
+	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+		num_ports);
 
 	/*
 	 * save off our num_ports info so that we can use it in the
@@ -887,8 +898,7 @@ static int clie_3_5_startup (struct usb_
  
 static int treo_attach (struct usb_serial *serial)
 {
-	struct usb_serial_port *port;
-	int i;
+	struct usb_serial_port swap_port;
 
 	/* Only do this endpoint hack for the Handspring devices with
 	 * interrupt in endpoints, which for now are the Treo devices. */
@@ -898,31 +908,40 @@ static int treo_attach (struct usb_seria
 
 	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;
-	}
+	/*
+	* It appears that Treos want to use the 1st interrupt endpoint to
+	* communicate with the 2nd bulk out endpoint, so let's swap the 1st
+	* and 2nd bulk in and interrupt endpoints.  Note that swapping the
+	* bulk out endpoints would break lots of apps that want to communicate
+	* on the second port.
+	*/
+	swap_port.read_urb = serial->port[0]->read_urb;
+	swap_port.bulk_in_endpointAddress = serial->port[0]->
+		bulk_in_endpointAddress;
+	swap_port.bulk_in_buffer = serial->port[0]->bulk_in_buffer;
+	swap_port.interrupt_in_urb = serial->port[0]->interrupt_in_urb;
+	swap_port.interrupt_in_endpointAddress = serial->port[0]->
+		interrupt_in_endpointAddress;
+	swap_port.interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
+ 
+	serial->port[0]->read_urb = serial->port[1]->read_urb;
+	serial->port[0]->bulk_in_endpointAddress = serial->port[1]->
+		bulk_in_endpointAddress;
+	serial->port[0]->bulk_in_buffer = serial->port[1]->bulk_in_buffer;
+	serial->port[0]->interrupt_in_urb = serial->port[1]->interrupt_in_urb;
+	serial->port[0]->interrupt_in_endpointAddress = serial->port[1]->
+		interrupt_in_endpointAddress;
+	serial->port[0]->interrupt_in_buffer = serial->port[1]->
+		interrupt_in_buffer;
+
+	serial->port[1]->read_urb = swap_port.read_urb;
+	serial->port[1]->bulk_in_endpointAddress = swap_port.
+		bulk_in_endpointAddress;
+	serial->port[1]->bulk_in_buffer = swap_port.bulk_in_buffer;
+	serial->port[1]->interrupt_in_urb = swap_port.interrupt_in_urb;
+	serial->port[1]->interrupt_in_endpointAddress = swap_port.
+		interrupt_in_endpointAddress;
+	serial->port[1]->interrupt_in_buffer = swap_port.interrupt_in_buffer;
 
 	return 0;
 }



-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 20:06                 ` Greg KH
  2004-05-24 20:21                   ` nardelli
@ 2004-05-25 13:15                   ` nardelli
  1 sibling, 0 replies; 26+ messages in thread
From: nardelli @ 2004-05-25 13:15 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> On Mon, May 24, 2004 at 03:38:58PM -0400, nardelli wrote:
> 
>>nardelli wrote:
>>
>>1) Whether writing to the 1st or 2nd port, the machine hangs pretty badly
>>after catting /dev/urandom for more than 1 second or two.  This continues
>>even after catting has stopped, and the device has been disconnected.  This
>>smells like some type of resource leak, probably memory, to me.
> 
> 
> Which machine dies?  The pilot or the Linux box?
> 
> 

Oops - missed this question earlier.  It's the linux box that dies.  The
pilot makes it through without a scratch - I'm a bit shocked, as they're
not exactly the most stable device.


-- 
Joe Nardelli
jnardelli@infosciences.com

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-24 21:42                 ` nardelli
@ 2004-05-25 18:30                   ` Greg KH
  2004-05-25 18:55                     ` nardelli
  0 siblings, 1 reply; 26+ messages in thread
From: Greg KH @ 2004-05-25 18:30 UTC (permalink / raw)
  To: nardelli; +Cc: linux-kernel, linux-usb-devel

On Mon, May 24, 2004 at 05:42:54PM -0400, nardelli wrote:
> Greg KH wrote:
> >
> >
> >Today, that call does fail:
> >
> >        if (!port->read_urb) {
> >                /* this is needed for some brain dead Sony devices */
> >                dev_err(&port->dev, "Device lied about number of ports, 
> >                please use a lower one.\n");
> >                return -ENODEV;
> >        }
> >
> >Let's not change that logic please.
> >
> 
> OK.
> 
> 
> Here's another patch.  The differences between this one and the last are:
> 
> 1) Removal of extra checks to verify that port->read_urb is valid
> 2) Modified num_ports initialization and return value checking in 
> palm_os_3_probe
> 
> 
> I made this patch against 2.6.6.  Would you prefer it against 2.6.7-rc1?

Nah, this is good enough.  I've tweaked the patch a bit to keep from
creating a big structure on the stack, and reduced the copy port logic
to something a bit more readable and applied this version.  I'll send it
off to Linus in a day or so.

Thanks a lot for your work on this.

greg k-h



--- 1.110/drivers/usb/serial/visor.c	2004-05-15 08:48:18 -07:00
+++ edited/drivers/usb/serial/visor.c	2004-05-25 11:19:19 -07:00
@@ -680,7 +680,7 @@
 	char *string;
 	int retval = 0;
 	int i;
-	int num_ports;
+	int num_ports = 0;
 
 	dbg("%s", __FUNCTION__);
 
@@ -702,41 +702,50 @@
 			__FUNCTION__, retval);
 		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;
-	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
-		connection_info->num_ports);
+	if (retval == sizeof(*connection_info)) {
+	        connection_info = (struct visor_connection_info *)transfer_buffer;
+
+		le16_to_cpus(&connection_info->num_ports);
+		num_ports = connection_info->num_ports;
 
-	for (i = 0; i < num_ports; ++i) {
-		switch (connection_info->connections[i].port_function_id) {
-			case VISOR_FUNCTION_GENERIC:
-				string = "Generic";
-				break;
-			case VISOR_FUNCTION_DEBUGGER:
-				string = "Debugger";
-				break;
-			case VISOR_FUNCTION_HOTSYNC:
-				string = "HotSync";
-				break;
-			case VISOR_FUNCTION_CONSOLE:
-				string = "Console";
-				break;
-			case VISOR_FUNCTION_REMOTE_FILE_SYS:
-				string = "Remote File System";
-				break;
-			default:
-				string = "unknown";
-				break;	
+		for (i = 0; i < num_ports; ++i) {
+			switch (connection_info->connections[i].port_function_id) {
+				case VISOR_FUNCTION_GENERIC:
+					string = "Generic";
+					break;
+				case VISOR_FUNCTION_DEBUGGER:
+					string = "Debugger";
+					break;
+				case VISOR_FUNCTION_HOTSYNC:
+					string = "HotSync";
+					break;
+				case VISOR_FUNCTION_CONSOLE:
+					string = "Console";
+					break;
+				case VISOR_FUNCTION_REMOTE_FILE_SYS:
+					string = "Remote File System";
+					break;
+				default:
+					string = "unknown";
+					break;
+			}
+			dev_info(dev, "%s: port %d, is for %s use\n",
+				serial->type->name,
+				connection_info->connections[i].port, string);
 		}
-		dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
-			 connection_info->connections[i].port, string);
 	}
+	/*
+	* Handle devices that report invalid stuff here.
+	*/
+	if (num_ports == 0 || num_ports > 2) {
+		dev_warn (dev, "%s: No valid connect info available\n",
+			serial->type->name);
+		num_ports = 2;
+	}
+  
+	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+		num_ports);
 
 	/*
 	 * save off our num_ports info so that we can use it in the
@@ -868,8 +877,7 @@
  
 static int treo_attach (struct usb_serial *serial)
 {
-	struct usb_serial_port *port;
-	int i;
+	struct usb_serial_port *swap_port;
 
 	/* Only do this endpoint hack for the Handspring devices with
 	 * interrupt in endpoints, which for now are the Treo devices. */
@@ -879,31 +887,28 @@
 
 	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;
-	}
+	/*
+	* It appears that Treos want to use the 1st interrupt endpoint to
+	* communicate with the 2nd bulk out endpoint, so let's swap the 1st
+	* and 2nd bulk in and interrupt endpoints.  Note that swapping the
+	* bulk out endpoints would break lots of apps that want to communicate
+	* on the second port.
+	*/
+#define COPY_PORT(dest, src)						\
+	dest->read_urb = src->read_urb;					\
+	dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;	\
+	dest->bulk_in_buffer = src->bulk_in_buffer;			\
+	dest->interrupt_in_urb = src->interrupt_in_urb;			\
+	dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress;	\
+	dest->interrupt_in_buffer = src->interrupt_in_buffer;
+
+	swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
+	if (!swap_port)
+		return -ENOMEM;
+	COPY_PORT(swap_port, serial->port[0]);
+	COPY_PORT(serial->port[0], serial->port[1]);
+	COPY_PORT(serial->port[1], swap_port);
+	kfree(swap_port);
 
 	return 0;
 }

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

* Re: [linux-usb-devel] [PATCH] visor: Fix Oops on disconnect
  2004-05-25 18:30                   ` Greg KH
@ 2004-05-25 18:55                     ` nardelli
  0 siblings, 0 replies; 26+ messages in thread
From: nardelli @ 2004-05-25 18:55 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, linux-usb-devel

Greg KH wrote:
> On Mon, May 24, 2004 at 05:42:54PM -0400, nardelli wrote:
> 
> 
> Nah, this is good enough.  I've tweaked the patch a bit to keep from
> creating a big structure on the stack, and reduced the copy port logic
> to something a bit more readable and applied this version.  I'll send it
> off to Linus in a day or so.
> 
> Thanks a lot for your work on this.
> 
> greg k-h
> 
> +#define COPY_PORT(dest, src)						\
> +	dest->read_urb = src->read_urb;					\
> +	dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;	\
> +	dest->bulk_in_buffer = src->bulk_in_buffer;			\
> +	dest->interrupt_in_urb = src->interrupt_in_urb;			\
> +	dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress;	\
> +	dest->interrupt_in_buffer = src->interrupt_in_buffer;
> +
> +	swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
> +	if (!swap_port)
> +		return -ENOMEM;
> +	COPY_PORT(swap_port, serial->port[0]);
> +	COPY_PORT(serial->port[0], serial->port[1]);
> +	COPY_PORT(serial->port[1], swap_port);
> +	kfree(swap_port);
>  
>  	return 0;
>  }
> -

That's definitely less error prone as well.

BTW - I appreciate the time that you have put into this, and especially 
the constructive comments and patience that you had regarding patches 
that I submitted.

-- 
Joe Nardelli
jnardelli@infosciences.com

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

end of thread, other threads:[~2004-05-25 18:55 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-05-20 23:08 [PATCH] visor: Fix Oops on disconnect nardelli
2004-05-21  4:30 ` [linux-usb-devel] " Greg KH
2004-05-21  5:03   ` Pete Zaitcev
2004-05-21 14:52     ` nardelli
2004-05-21 14:48   ` nardelli
2004-05-21 15:05     ` Alan Stern
2004-05-21 17:08       ` nardelli
2004-05-21 15:41     ` Greg KH
2004-05-21 19:51   ` nardelli
2004-05-21 20:01     ` jkroon
2004-05-21 20:22       ` nardelli
2004-05-21 20:44     ` Greg KH
2004-05-21 21:44       ` nardelli
2004-05-21 21:56         ` Greg KH
2004-05-21 22:04         ` nardelli
2004-05-21 22:30           ` Greg KH
2004-05-24 17:20             ` nardelli
2004-05-24 19:38               ` nardelli
2004-05-24 20:06                 ` Greg KH
2004-05-24 20:21                   ` nardelli
2004-05-25 13:15                   ` nardelli
2004-05-24 20:08               ` Greg KH
2004-05-24 21:42                 ` nardelli
2004-05-25 18:30                   ` Greg KH
2004-05-25 18:55                     ` nardelli
2004-05-21  4:31 ` 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).