Commit ff9f1839 authored by Joe Nardelli's avatar Joe Nardelli Committed by Greg Kroah-Hartman

[PATCH] USB: visor: Fix Oops on disconnect

This fixes http://bugme.osdl.org/show_bug.cgi?id=2289

This patch has been tweaked by greg@kroah.com
parent 3a386413
...@@ -680,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -680,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
char *string; char *string;
int retval = 0; int retval = 0;
int i; int i;
int num_ports; int num_ports = 0;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
...@@ -702,41 +702,50 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -702,41 +702,50 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
__FUNCTION__, retval); __FUNCTION__, retval);
goto exit; 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) { if (retval == sizeof(*connection_info)) {
switch (connection_info->connections[i].port_function_id) { connection_info = (struct visor_connection_info *)transfer_buffer;
case VISOR_FUNCTION_GENERIC:
string = "Generic"; le16_to_cpus(&connection_info->num_ports);
break; num_ports = connection_info->num_ports;
case VISOR_FUNCTION_DEBUGGER:
string = "Debugger"; for (i = 0; i < num_ports; ++i) {
break; switch (connection_info->connections[i].port_function_id) {
case VISOR_FUNCTION_HOTSYNC: case VISOR_FUNCTION_GENERIC:
string = "HotSync"; string = "Generic";
break; break;
case VISOR_FUNCTION_CONSOLE: case VISOR_FUNCTION_DEBUGGER:
string = "Console"; string = "Debugger";
break; break;
case VISOR_FUNCTION_REMOTE_FILE_SYS: case VISOR_FUNCTION_HOTSYNC:
string = "Remote File System"; string = "HotSync";
break; break;
default: case VISOR_FUNCTION_CONSOLE:
string = "unknown"; string = "Console";
break; 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 * save off our num_ports info so that we can use it in the
...@@ -868,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial) ...@@ -868,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
static int treo_attach (struct usb_serial *serial) static int treo_attach (struct usb_serial *serial)
{ {
struct usb_serial_port *port; struct usb_serial_port *swap_port;
int i;
/* Only do this endpoint hack for the Handspring devices with /* Only do this endpoint hack for the Handspring devices with
* interrupt in endpoints, which for now are the Treo devices. */ * interrupt in endpoints, which for now are the Treo devices. */
...@@ -879,31 +887,28 @@ static int treo_attach (struct usb_serial *serial) ...@@ -879,31 +887,28 @@ static int treo_attach (struct usb_serial *serial)
dbg("%s", __FUNCTION__); 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 * It appears that Treos want to use the 1st interrupt endpoint to
* "virtual serial port". So let's force the endpoints to be * communicate with the 2nd bulk out endpoint, so let's swap the 1st
* where we want them to be. */ * and 2nd bulk in and interrupt endpoints. Note that swapping the
for (i = serial->num_bulk_in; i < serial->num_ports; ++i) { * bulk out endpoints would break lots of apps that want to communicate
port = serial->port[i]; * on the second port.
port->read_urb = serial->port[0]->read_urb; */
port->bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress; #define COPY_PORT(dest, src) \
port->bulk_in_buffer = serial->port[0]->bulk_in_buffer; dest->read_urb = src->read_urb; \
} dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress; \
dest->bulk_in_buffer = src->bulk_in_buffer; \
for (i = serial->num_bulk_out; i < serial->num_ports; ++i) { dest->interrupt_in_urb = src->interrupt_in_urb; \
port = serial->port[i]; dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress; \
port->write_urb = serial->port[0]->write_urb; dest->interrupt_in_buffer = src->interrupt_in_buffer;
port->bulk_out_size = serial->port[0]->bulk_out_size;
port->bulk_out_endpointAddress = serial->port[0]->bulk_out_endpointAddress; swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
port->bulk_out_buffer = serial->port[0]->bulk_out_buffer; if (!swap_port)
} return -ENOMEM;
COPY_PORT(swap_port, serial->port[0]);
for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) { COPY_PORT(serial->port[0], serial->port[1]);
port = serial->port[i]; COPY_PORT(serial->port[1], swap_port);
port->interrupt_in_urb = serial->port[0]->interrupt_in_urb; kfree(swap_port);
port->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
port->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment