This patch adds equal support for interrupt out transfers to the usb-serial core to 
match the current interrupt in support.  It also improves a few debug messages, 
nothing major.  This is necessary for the cypress_m8 driver being released 9/30/04.

Signed-off-by: Lonnie Mendez <[EMAIL PROTECTED]>

--- a/drivers/usb/serial/usb-serial.c	2004-09-30 16:18:43.146802216 -0500
+++ b/drivers/usb/serial/usb-serial.c	2004-09-30 16:19:50.229604080 -0500
@@ -466,9 +466,14 @@
 				usb_unlink_urb(port->interrupt_in_urb);
 				usb_free_urb(port->interrupt_in_urb);
 			}
+			if (port->interrupt_out_urb) {
+				usb_unlink_urb(port->interrupt_out_urb);
+				usb_free_urb(port->interrupt_out_urb);
+			}
 			kfree(port->bulk_in_buffer);
 			kfree(port->bulk_out_buffer);
 			kfree(port->interrupt_in_buffer);
+			kfree(port->interrupt_out_buffer);
 		}
 	}
 
@@ -825,9 +830,14 @@
 		usb_unlink_urb(port->interrupt_in_urb);
 		usb_free_urb(port->interrupt_in_urb);
 	}
+	if (port->interrupt_out_urb) {
+		usb_unlink_urb(port->interrupt_out_urb);
+		usb_free_urb(port->interrupt_out_urb);
+	}
 	kfree(port->bulk_in_buffer);
 	kfree(port->bulk_out_buffer);
 	kfree(port->interrupt_in_buffer);
+	kfree(port->interrupt_out_buffer);
 	kfree(port);
 }
 
@@ -862,6 +872,7 @@
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
+	struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
 	struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
 	struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
 	struct usb_serial_device_type *type = NULL;
@@ -872,6 +883,7 @@
 	int buffer_size;
 	int i;
 	int num_interrupt_in = 0;
+	int num_interrupt_out = 0;
 	int num_bulk_in = 0;
 	int num_bulk_out = 0;
 	int num_ports = 0;
@@ -928,7 +940,7 @@
 		if ((endpoint->bEndpointAddress & 0x80) &&
 		    ((endpoint->bmAttributes & 3) == 0x02)) {
 			/* we found a bulk in endpoint */
-			dbg("found bulk in");
+			dbg("found bulk in on endpoint %d", i);
 			bulk_in_endpoint[num_bulk_in] = endpoint;
 			++num_bulk_in;
 		}
@@ -936,7 +948,7 @@
 		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
 		    ((endpoint->bmAttributes & 3) == 0x02)) {
 			/* we found a bulk out endpoint */
-			dbg("found bulk out");
+			dbg("found bulk out on endpoint %d", i);
 			bulk_out_endpoint[num_bulk_out] = endpoint;
 			++num_bulk_out;
 		}
@@ -944,10 +956,18 @@
 		if ((endpoint->bEndpointAddress & 0x80) &&
 		    ((endpoint->bmAttributes & 3) == 0x03)) {
 			/* we found a interrupt in endpoint */
-			dbg("found interrupt in");
+			dbg("found interrupt in on endpoint %d", i);
 			interrupt_in_endpoint[num_interrupt_in] = endpoint;
 			++num_interrupt_in;
 		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found an interrupt out endpoint */
+			dbg("found interrupt out on endpoint %d", i);
+			interrupt_out_endpoint[num_interrupt_out] = endpoint;
+			++num_interrupt_out;
+		}
 	}
 
 #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
@@ -1024,11 +1044,13 @@
 	serial->num_bulk_in = num_bulk_in;
 	serial->num_bulk_out = num_bulk_out;
 	serial->num_interrupt_in = num_interrupt_in;
+	serial->num_interrupt_out = num_interrupt_out;
 
 	/* create our ports, we need as many as the max endpoints */
 	/* 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);
+	max_endpoints = max(max_endpoints, num_interrupt_out);
 	max_endpoints = max(max_endpoints, (int)serial->num_ports);
 	serial->num_port_pointers = max_endpoints;
 	dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
@@ -1091,29 +1113,61 @@
 				   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, GFP_KERNEL);
-		if (!port->interrupt_in_urb) {
-			dev_err(&interface->dev, "No free urbs available\n");
-			goto probe_error;
+	if (serial->type->read_int_callback) {
+		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, GFP_KERNEL);
+			if (!port->interrupt_in_urb) {
+				dev_err(&interface->dev, "No free urbs available\n");
+				goto probe_error;
+			}
+			buffer_size = endpoint->wMaxPacketSize;
+			port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
+			port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+			if (!port->interrupt_in_buffer) {
+				dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
+				goto probe_error;
+			}
+			usb_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);
 		}
-		buffer_size = endpoint->wMaxPacketSize;
-		port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
-		port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-		if (!port->interrupt_in_buffer) {
-			dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
-			goto probe_error;
+	} else if (num_interrupt_in) {
+		dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
+	}
+	
+	if (serial->type->write_int_callback) {
+		for (i = 0; i < num_interrupt_out; ++i) {
+			endpoint = interrupt_out_endpoint[i];
+			port = serial->port[i];
+			port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+			if (!port->interrupt_out_urb) {
+				dev_err(&interface->dev, "No free urbs available\n");
+				goto probe_error;
+			}
+			buffer_size = endpoint->wMaxPacketSize;
+			port->interrupt_out_size = buffer_size;
+			port->interrupt_out_endpointAddress = endpoint->bEndpointAddress;
+			port->interrupt_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+			if (!port->interrupt_out_buffer) {
+				dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n");
+				goto probe_error;
+			}
+			usb_fill_int_urb (port->interrupt_out_urb, dev,
+					  usb_sndintpipe (dev,
+							  endpoint->bEndpointAddress),
+					  port->interrupt_out_buffer, buffer_size,
+					  serial->type->write_int_callback, port,
+					  endpoint->bInterval);
 		}
-		usb_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);
+	} else if (num_interrupt_out) {
+		dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
 	}
-
+	
 	/* if this device type has an attach function, call it */
 	if (type->attach) {
 		if (!try_module_get(type->owner)) {
@@ -1176,6 +1230,14 @@
 			usb_free_urb (port->interrupt_in_urb);
 		kfree(port->interrupt_in_buffer);
 	}
+	for (i = 0; i < num_interrupt_out; ++i) {
+		port = serial->port[i];
+		if (!port)
+			continue;
+		if (port->interrupt_out_urb)
+			usb_free_urb (port->interrupt_out_urb);
+		kfree(port->interrupt_out_buffer);
+	}
 
 	/* return the minor range that this device had */
 	return_serial (serial);
--- a/drivers/usb/serial/usb-serial.h	2004-08-14 05:56:25.000000000 -0500
+++ b/drivers/usb/serial/usb-serial.h	2004-09-30 16:19:50.242602104 -0500
@@ -74,6 +74,11 @@
  * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
  * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe
  *	for this port.
+ * @interrupt_out_buffer: pointer to the interrupt out buffer for this port.
+ * @interrupt_out_size: the size of the interrupt_out_buffer, in bytes.
+ * @interrupt_out_urb: pointer to the interrupt out struct urb for this port.
+ * @interrupt_out_endpointAddress: endpoint address for the interrupt out pipe
+ * 	for this port.
  * @bulk_in_buffer: pointer to the bulk in buffer for this port.
  * @read_urb: pointer to the bulk in struct urb for this port.
  * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
@@ -99,6 +104,11 @@
 	struct urb *		interrupt_in_urb;
 	__u8			interrupt_in_endpointAddress;
 
+	unsigned char *		interrupt_out_buffer;
+	int			interrupt_out_size;
+	struct urb *		interrupt_out_urb;
+	__u8			interrupt_out_endpointAddress;
+
 	unsigned char *		bulk_in_buffer;
 	struct urb *		read_urb;
 	__u8			bulk_in_endpointAddress;
@@ -134,6 +144,7 @@
  * @minor: the starting minor number for this device
  * @num_ports: the number of ports this device has
  * @num_interrupt_in: number of interrupt in endpoints we have
+ * @num_interrupt_out: number of interrupt out endpoints we have
  * @num_bulk_in: number of bulk in endpoints we have
  * @num_bulk_out: number of bulk out endpoints we have
  * @vendor: vendor id of this device
@@ -152,6 +163,7 @@
 	unsigned char			num_ports;
 	unsigned char			num_port_pointers;
 	char				num_interrupt_in;
+	char				num_interrupt_out;
 	char				num_bulk_in;
 	char				num_bulk_out;
 	__u16				vendor;
@@ -187,6 +199,8 @@
  *	of the devices this structure can support.
  * @num_interrupt_in: the number of interrupt in endpoints this device will
  *	have.
+ * @num_interrupt_out: the number of interrupt out endpoints this device will
+ *	have.
  * @num_bulk_in: the number of bulk in endpoints this device will have.
  * @num_bulk_out: the number of bulk out endpoints this device will have.
  * @num_ports: the number of different ports this device will have.
@@ -219,6 +233,7 @@
 	char	*short_name;
 	const struct usb_device_id *id_table;
 	char	num_interrupt_in;
+	char	num_interrupt_out;
 	char	num_bulk_in;
 	char	num_bulk_out;
 	char	num_ports;
@@ -250,6 +265,7 @@
 	int  (*tiocmset)	(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
 
 	void (*read_int_callback)(struct urb *urb, struct pt_regs *regs);
+	void (*write_int_callback)(struct urb *urb, struct pt_regs *regs);
 	void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
 	void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
 };

Reply via email to