patch-2.3.99-pre6 linux/drivers/usb/serial/usbserial.c

Next file: linux/drivers/usb/uhci-debug.h
Previous file: linux/drivers/usb/serial/usb-serial.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
@@ -14,6 +14,14 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (04/23/2000) gkh
+ *	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
+ *	Moved when the startup code printed out the devices that are supported.
+ *
+ * (04/19/2000) gkh
+ *	Added driver for ZyXEL omni.net lcd plus ISDN TA
+ *	Made startup info message specify which drivers were compiled in.
+ *
  * (04/03/2000) gkh
  *	Changed the probe process to remove the module unload races.
  *	Changed where the tty layer gets initialized to have devfs work nicer.
@@ -211,6 +219,7 @@
 
 #include "usb-serial.h"
 
+#define MAX(a,b)	(((a)>(b))?(a):(b))
 
 /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
 /* need to always compile these in, as some of the other devices use these functions as their own. */
@@ -270,6 +279,9 @@
 	&keyspan_pda_fake_device,
 	&keyspan_pda_device,
 #endif
+#ifdef CONFIG_USB_SERIAL_OMNINET
+	&zyxel_omninet_device,
+#endif
 	NULL
 };
 
@@ -424,14 +436,9 @@
 		return -ENODEV;
 	}
 
-	/* set up our port structure */
+	/* set up our port structure making the tty driver remember our port object, and us it */
 	portNumber = MINOR(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
-	port->number = portNumber;
-	port->serial = serial;
-	port->magic = USB_SERIAL_PORT_MAGIC;
-	
-	/* make the tty driver remember our port object, and us it */
 	tty->driver_data = port;
 	port->tty = tty;
 	 
@@ -996,236 +1003,248 @@
 	int num_bulk_in = 0;
 	int num_bulk_out = 0;
 	int num_ports;
+	int max_endpoints;
 	
-	/* loop through our list of known serial converters, and see if this device matches */
-	device_num = 0;
-	while (usb_serial_devices[device_num] != NULL) {
+	/* loop through our list of known serial converters, and see if this
+           device matches. */
+	for (device_num = 0; usb_serial_devices[device_num]; device_num++) {
 		type = usb_serial_devices[device_num];
-		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", 
+		     type->name, *(type->idVendor), *(type->idProduct));
 
 		/* look at the device descriptor */
 		if ((dev->descriptor.idVendor == *(type->idVendor)) &&
 		    (dev->descriptor.idProduct == *(type->idProduct))) {
+			dbg("descriptor matches");
+			break;
+		}
+	}
+	if (!usb_serial_devices[device_num]) {
+		/* no match */
+		dbg("none matched");
+		return(NULL);
+	}
 
-			dbg("descriptor matches...looking at the endpoints");
-
-			/* descriptor matches, let's try to find the endpoints needed */
-			interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+	/* descriptor matches, let's find the endpoints needed */
+	interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
 			
-			/* check out the endpoints */
-			interface = &dev->actconfig->interface[ifnum].altsetting[0];
-			for (i = 0; i < interface->bNumEndpoints; ++i) {
-				endpoint = &interface->endpoint[i];
-		
-				if ((endpoint->bEndpointAddress & 0x80) &&
-				    ((endpoint->bmAttributes & 3) == 0x02)) {
-					/* we found a bulk in endpoint */
-					dbg("found bulk in");
-					bulk_in_pipe = HAS;
-					bulk_in_endpoint[num_bulk_in] = endpoint;
-					++num_bulk_in;
-				}
-
-				if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-				    ((endpoint->bmAttributes & 3) == 0x02)) {
-					/* we found a bulk out endpoint */
-					dbg("found bulk out");
-					bulk_out_pipe = HAS;
-					bulk_out_endpoint[num_bulk_out] = endpoint;
-					++num_bulk_out;
-				}
+	/* check out the endpoints */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	for (i = 0; i < interface->bNumEndpoints; ++i) {
+		endpoint = &interface->endpoint[i];
 		
-				if ((endpoint->bEndpointAddress & 0x80) &&
-				    ((endpoint->bmAttributes & 3) == 0x03)) {
-					/* we found a interrupt in endpoint */
-					dbg("found interrupt in");
-					interrupt_pipe = HAS;
-					interrupt_in_endpoint[num_interrupt_in] = endpoint;
-					++num_interrupt_in;
-				}
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk in endpoint */
+			dbg("found bulk in");
+			bulk_in_pipe = HAS;
+			bulk_in_endpoint[num_bulk_in] = endpoint;
+			++num_bulk_in;
+		}
 
-			}
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk out endpoint */
+			dbg("found bulk out");
+			bulk_out_pipe = HAS;
+			bulk_out_endpoint[num_bulk_out] = endpoint;
+			++num_bulk_out;
+		}
+		
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found a interrupt in endpoint */
+			dbg("found interrupt in");
+			interrupt_pipe = HAS;
+			interrupt_in_endpoint[num_interrupt_in] = endpoint;
+			++num_interrupt_in;
+		}
+	}
 	
-			/* verify that we found all of the endpoints that we need */
-			if ((interrupt_pipe & type->needs_interrupt_in) &&
-			    (bulk_in_pipe & type->needs_bulk_in) &&
-			    (bulk_out_pipe & type->needs_bulk_out)) {
-				/* found all that we need */
-				MOD_INC_USE_COUNT;
-				info("%s converter detected", type->name);
+	/* verify that we found all of the endpoints that we need */
+	if (!((interrupt_pipe & type->needs_interrupt_in) &&
+	      (bulk_in_pipe & type->needs_bulk_in) &&
+	      (bulk_out_pipe & type->needs_bulk_out))) {
+		/* nope, they don't match what we expected */
+		info("descriptors matched, but endpoints did not");
+		return NULL;
+	}
 
-#ifdef CONFIG_USB_SERIAL_GENERIC
-				if (type == &generic_device)
-					num_ports = num_bulk_out;
-				else
-#endif
-					num_ports = type->num_ports;
+	/* found all that we need */
+	MOD_INC_USE_COUNT;
+	info("%s converter detected", type->name);
 
-				serial = get_free_serial (num_ports, &minor);
-				if (serial == NULL) {
-					err("No more free serial devices");
-					MOD_DEC_USE_COUNT;
-					return NULL;
-				}
-	
-			       	serial->dev = dev;
-				serial->type = type;
-				serial->minor = minor;
-				serial->num_ports = num_ports;
-				serial->num_bulk_in = num_bulk_in;
-				serial->num_bulk_out = num_bulk_out;
-				serial->num_interrupt_in = num_interrupt_in;
-
-				/* initialize a tty_driver for this device */
-				serial->tty_driver = usb_serial_tty_driver_init (serial);
-				if (serial->tty_driver == NULL) {
-					err("Can't create a tty_serial_driver");
-					goto probe_error;
-				}
-
-				if (tty_register_driver (serial->tty_driver)) {
-					err("failed to register tty driver");
-					goto probe_error;
-				}
-
-				/* collect interrupt_in endpoints now, because
-				   the keyspan_pda startup function needs
-				   to know about them */
-				for (i = 0; i < num_interrupt_in; ++i) {
-					port = &serial->port[i];
-					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
-					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->interrupt_in_buffer) {
-						err("Couldn't allocate interrupt_in_buffer");
-						goto probe_error;
-					}
-					port->interrupt_in_endpoint = interrupt_in_endpoint[i];
-				}
-
-				/* if this device type has a startup function, call it */
-				if (type->startup) {
-					if (type->startup (serial)) {
-						goto probe_error;
-					}
-				}
-
-				/* set up the endpoint information */
-				for (i = 0; i < num_bulk_in; ++i) {
-					port = &serial->port[i];
-					port->read_urb = usb_alloc_urb (0);
-					if (!port->read_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
-					port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->bulk_in_buffer) {
-						err("Couldn't allocate bulk_in_buffer");
-						goto probe_error;
-					}
-					if (serial->type->read_bulk_callback) {
-						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
-					} else {
-						FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
-								port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
-					}
-				}
-
-				for (i = 0; i < num_bulk_out; ++i) {
-					port = &serial->port[i];
-					port->write_urb = usb_alloc_urb(0);
-					if (!port->write_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
-					port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
-					if (!port->bulk_out_buffer) {
-						err("Couldn't allocate bulk_out_buffer");
-						goto probe_error;
-					}
-					if (serial->type->write_bulk_callback) {
-						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
-					} else {
-						FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
-								port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
-					}
-				}
-
-#if 0 /* use this code when WhiteHEAT is up and running */
-				for (i = 0; i < num_interrupt_in; ++i) {
-					port = &serial->port[i];
-					port->control_urb = usb_alloc_urb(0);
-					if (!port->control_urb) {
-						err("No free urbs available");
-						goto probe_error;
-					}
-					buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
-					port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-					if (!port->interrupt_in_buffer) {
-						err("Couldn't allocate interrupt_in_buffer");
-						goto probe_error;
-					}
-					FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
-							port->interrupt_in_buffer, buffer_size, serial_control_irq,
-							port, interrupt_in_endpoint[i]->bInterval);
-				}
+#ifdef CONFIG_USB_SERIAL_GENERIC
+	if (type == &generic_device) {
+		num_ports = num_bulk_out;
+		if (num_ports == 0) {
+			err("Generic device with no bulk out, not allowed.");
+			MOD_DEC_USE_COUNT;
+			return NULL;
+		}
+	} else
 #endif
+		num_ports = type->num_ports;
 
-				for (i = 0; i < serial->num_ports; ++i) {
-					info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
-				}
-
-				return serial;
-			} else {
-				info("descriptors matched, but endpoints did not");
-			}
+	serial = get_free_serial (num_ports, &minor);
+	if (serial == NULL) {
+		err("No more free serial devices");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	
+	serial->dev = dev;
+	serial->type = type;
+	serial->minor = minor;
+	serial->num_ports = num_ports;
+	serial->num_bulk_in = num_bulk_in;
+	serial->num_bulk_out = num_bulk_out;
+	serial->num_interrupt_in = num_interrupt_in;
+
+	/* initialize a tty_driver for this device */
+	serial->tty_driver = usb_serial_tty_driver_init (serial);
+	if (serial->tty_driver == NULL) {
+		err("Can't create a tty_serial_driver");
+		goto probe_error;
+	}
+
+	if (tty_register_driver (serial->tty_driver)) {
+		err("failed to register tty driver");
+		goto probe_error;
+	}
+	
+	/* if this device type has a startup function, call it */
+	if (type->startup) {
+		if (type->startup (serial)) {
+			goto probe_error;
 		}
-
-		/* look at the next type in our list */
-		++device_num;
 	}
 
-probe_error:
-	if (serial) {
-		for (i = 0; i < num_bulk_in; ++i) {
-			port = &serial->port[i];
-			if (port->read_urb)
-				usb_free_urb (port->read_urb);
-			if (serial->port[i].bulk_in_buffer[i])
-				kfree (serial->port[i].bulk_in_buffer);
+	/* set up the endpoint information */
+	for (i = 0; i < num_bulk_in; ++i) {
+		endpoint = bulk_in_endpoint[i];
+		port = &serial->port[i];
+		port->read_urb = usb_alloc_urb (0);
+		if (!port->read_urb) {
+			err("No free urbs available");
+			goto probe_error;
 		}
-		for (i = 0; i < num_bulk_out; ++i) {
-			port = &serial->port[i];
-			if (port->write_urb)
-				usb_free_urb (port->write_urb);
-			if (serial->port[i].bulk_out_buffer)
-				kfree (serial->port[i].bulk_out_buffer);
+		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->bulk_in_buffer) {
+			err("Couldn't allocate bulk_in_buffer");
+			goto probe_error;
 		}
-		for (i = 0; i < num_interrupt_in; ++i) {
-			port = &serial->port[i];
-			if (port->control_urb)
-				usb_free_urb (port->control_urb);
-			if (serial->port[i].interrupt_in_buffer)
-				kfree (serial->port[i].interrupt_in_buffer);
+		FILL_BULK_URB(port->read_urb, dev, 
+			      usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+			      port->bulk_in_buffer, buffer_size, 
+			      ((serial->type->read_bulk_callback) ?
+			       serial->type->read_bulk_callback :
+			       generic_read_bulk_callback), 
+			      port);
+	}
+
+	for (i = 0; i < num_bulk_out; ++i) {
+		endpoint = bulk_out_endpoint[i];
+		port = &serial->port[i];
+		port->write_urb = usb_alloc_urb(0);
+		if (!port->write_urb) {
+			err("No free urbs available");
+			goto probe_error;
 		}
-		
-		/* return the minor range that this device had */
-		return_serial (serial);
-
-		/* if this device has a tty_driver, then unregister it and free it */
-		if (serial->tty_driver) {
-			tty_unregister_driver (serial->tty_driver);
-			kfree (serial->tty_driver);
-			serial->tty_driver = NULL;
+		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_out_size = buffer_size;
+		port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->bulk_out_buffer) {
+			err("Couldn't allocate bulk_out_buffer");
+			goto probe_error;
+		}
+		FILL_BULK_URB(port->write_urb, dev, 
+			      usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
+			      port->bulk_out_buffer, buffer_size,
+			      ((serial->type->write_bulk_callback) ? 
+			       serial->type->write_bulk_callback : 
+			       generic_write_bulk_callback), 
+			      port);
+	}
+
+	for (i = 0; i < num_interrupt_in; ++i) {
+		endpoint = interrupt_in_endpoint[i];
+		port = &serial->port[i];
+		port->interrupt_in_urb = usb_alloc_urb(0);
+		if (!port->interrupt_in_urb) {
+			err("No free urbs available");
+			goto probe_error;
 		}
+		buffer_size = endpoint->wMaxPacketSize;
+		port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->interrupt_in_buffer) {
+			err("Couldn't allocate interrupt_in_buffer");
+			goto probe_error;
+		}
+		FILL_INT_URB(port->interrupt_in_urb, dev, 
+			     usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+			     port->interrupt_in_buffer, buffer_size, 
+			     serial->type->read_int_callback,
+			     port, 
+			     endpoint->bInterval);
+	}
+
+	/* initialize some parts of the port structures */
+	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
+	max_endpoints = MAX(num_bulk_in, num_bulk_out);
+	max_endpoints = MAX(max_endpoints, num_interrupt_in);
+	for (i = 0; i < max_endpoints; ++i) {
+		port = &serial->port[i];
+		port->number = i;
+		port->serial = serial;
+		port->magic = USB_SERIAL_PORT_MAGIC;
+	}
+	
+	for (i = 0; i < serial->num_ports; ++i) {
+		info("%s converter now attached to ttyUSB%d", 
+		     type->name, serial->minor + i);
+	}
+	
+	return serial; /* success */
 
-		/* free up any memory that we allocated */
-		kfree (serial);
-		MOD_DEC_USE_COUNT;
+
+probe_error:
+	for (i = 0; i < num_bulk_in; ++i) {
+		port = &serial->port[i];
+		if (port->read_urb)
+			usb_free_urb (port->read_urb);
+		if (port->bulk_in_buffer)
+			kfree (port->bulk_in_buffer);
+	}
+	for (i = 0; i < num_bulk_out; ++i) {
+		port = &serial->port[i];
+		if (port->write_urb)
+			usb_free_urb (port->write_urb);
+		if (port->bulk_out_buffer)
+			kfree (port->bulk_out_buffer);
+	}
+	for (i = 0; i < num_interrupt_in; ++i) {
+		port = &serial->port[i];
+		if (port->interrupt_in_urb)
+			usb_free_urb (port->interrupt_in_urb);
+		if (port->interrupt_in_buffer)
+			kfree (port->interrupt_in_buffer);
 	}
+		
+	/* return the minor range that this device had */
+	return_serial (serial);
+
+	/* if this device has a tty_driver, then unregister it and free it */
+	if (serial->tty_driver) {
+		tty_unregister_driver (serial->tty_driver);
+		kfree (serial->tty_driver);
+		serial->tty_driver = NULL;
+	}
+
+	/* free up any memory that we allocated */
+	kfree (serial);
+	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -1237,6 +1256,9 @@
 	int i;
 
 	if (serial) {
+		if (serial->type->shutdown)
+			serial->type->shutdown(serial);
+
 		for (i = 0; i < serial->num_ports; ++i)
 			serial->port[i].active = 0;
 
@@ -1260,9 +1282,9 @@
 		}
 		for (i = 0; i < serial->num_interrupt_in; ++i) {
 			port = &serial->port[i];
-			if (port->control_urb) {
-				usb_unlink_urb (port->control_urb);
-				usb_free_urb (port->control_urb);
+			if (port->interrupt_in_urb) {
+				usb_unlink_urb (port->interrupt_in_urb);
+				usb_free_urb (port->interrupt_in_urb);
 			}
 			if (port->interrupt_in_buffer)
 				kfree (port->interrupt_in_buffer);
@@ -1295,18 +1317,32 @@
 int usb_serial_init(void)
 {
 	int i;
+	int something;
+	int result;
 
 	/* Initalize our global data */
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		serial_table[i] = NULL;
 	}
 
+	/* tell the world what devices this driver currently supports */
+	something = 0;
+	for (i = 0; usb_serial_devices[i]; ++i) {
+		if (!strstr (usb_serial_devices[i]->name, "prerenumeration")) {
+			info ("USB Serial support registered for %s", usb_serial_devices[i]->name);
+			something = 1;
+		}
+	}
+	if (!something)
+		info ("USB Serial driver is not configured for any devices!");
+
 	/* register the USB driver */
-	if (usb_register(&usb_serial_driver) < 0) {
+	result = usb_register(&usb_serial_driver);
+	if (result < 0) {
+		err("usb_register failed for the usb-serial driver. Error number %d", result);
 		return -1;
 	}
-
-	info("support registered");
+	
 	return 0;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)