patch-2.4.15 linux/drivers/usb/serial/io_edgeport.c

Next file: linux/drivers/usb/serial/io_tables.h
Previous file: linux/drivers/usb/serial/ftdi_sio.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
@@ -25,6 +25,14 @@
  *
  * Version history:
  * 
+ * 2.2 2001_11_14 greg kroah-hartman
+ *	- fixed bug in edge_close that kept the port from being used more
+ *	  than once.
+ *	- fixed memory leak on device removal.
+ *	- fixed potential double free of memory when command urb submitting
+ *	  failed.
+ *	- other small cleanups when the device is removed
+ *	
  * 2.1 2001_07_09 greg kroah-hartman
  *	- added support for TIOCMBIS and TIOCMBIC.
  *
@@ -263,7 +271,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.1"
+#define DRIVER_VERSION "v2.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
 #define DRIVER_DESC "Edgeport USB Serial Driver"
 
@@ -433,7 +441,7 @@
 
 /* function prototypes for all URB callbacks */
 static void edge_interrupt_callback	(struct urb *urb);
-static void edge_bulk_in_callback		(struct urb *urb);
+static void edge_bulk_in_callback	(struct urb *urb);
 static void edge_bulk_out_data_callback	(struct urb *urb);
 static void edge_bulk_out_cmd_callback	(struct urb *urb);
 
@@ -646,12 +654,6 @@
 }
 #endif
 
-
-
-/************************************************************************
- *																		*
- *																		*
- ************************************************************************/
 static void get_product_info(struct edgeport_serial *edge_serial)
 {
 	struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -933,7 +935,7 @@
 	dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs);
 
 
-	/* if this urb had a transfer buffer already (old transfer) free it */
+	/* clean up the transfer buffer */
 	if (urb->transfer_buffer != NULL) {
 		kfree(urb->transfer_buffer);
 	}
@@ -957,7 +959,6 @@
 	/* tell the tty driver that something has changed */
 	wake_up_interruptible(&tty->write_wait);
 
-
 	/* we have completed the command */
 	edge_port->commandPending = FALSE;
 	wake_up_interruptible(&edge_port->wait_command);
@@ -987,6 +988,9 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	if (edge_port == NULL)
+		return -ENODEV;
+
 	++port->open_count;
 	MOD_INC_USE_COUNT;
 	
@@ -1002,6 +1006,12 @@
 		   as the structures were not set up at that time.) */
 		serial = port->serial;
 		edge_serial = (struct edgeport_serial *)serial->private;
+		if (edge_serial == NULL) {
+			port->active = 0;
+			port->open_count = 0;
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
 		if (edge_serial->interrupt_in_buffer == NULL) {
 			struct usb_serial_port *port0 = &serial->port[0];
 			
@@ -1015,25 +1025,22 @@
 			edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
 		
 			/* set up our interrupt urb */
-			/* Like to use FILL_INT_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */
-			edge_serial->interrupt_read_urb->complete = edge_interrupt_callback;
-			edge_serial->interrupt_read_urb->context = edge_serial;
-			/* FILL_INT_URB(edge_serial->interrupt_read_urb, serial->dev, 
-				     usb_rcvintpipe (serial->dev, edge_serial->interrupt_in_endpoint),
-				     edge_serial->interrupt_in_buffer, edge_serial->interrupt_in_endpoint.wMaxPacketSize,
-				     edge_interrupt_callback, edge_serial, edge_serial->interrupt_in_endpoint.bInterval);
-			*/
+			FILL_INT_URB(edge_serial->interrupt_read_urb,
+				     serial->dev,
+				     usb_rcvintpipe(serial->dev,
+					            port0->interrupt_in_endpointAddress),
+				     port0->interrupt_in_buffer,
+				     edge_serial->interrupt_read_urb->transfer_buffer_length,
+				     edge_interrupt_callback, edge_serial,
+				     edge_serial->interrupt_read_urb->interval);
 			
 			/* set up our bulk in urb */
-			/* Like to use FILL_BULK_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */
-			edge_serial->read_urb->complete = edge_bulk_in_callback;
-			edge_serial->read_urb->context = edge_serial;
-			/* FILL_BULK_URB(edge_serial->read_urb, serial->dev, 
-				      usb_rcvbulkpipe (serial->dev, edge_serial->bulk_in_endpoint),
-				      edge_serial->bulk_in_buffer, edge_serial->bulk_in_endpoint->wMaxPacketSize,
+			FILL_BULK_URB(edge_serial->read_urb, serial->dev,
+				      usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
+				      port0->bulk_in_buffer,
+				      edge_serial->read_urb->transfer_buffer_length,
 				      edge_bulk_in_callback, edge_serial);
-			*/
-		
+
 			/* start interrupt read for this edgeport
 			 * this interrupt will continue as long as the edgeport is connected */
 			response = usb_submit_urb (edge_serial->interrupt_read_urb);
@@ -1237,7 +1244,9 @@
 	
 	edge_serial = (struct edgeport_serial *)serial->private;
 	edge_port = (struct edgeport_port *)port->private;
-
+	if ((edge_serial == NULL) || (edge_port == NULL))
+		return;
+	
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -1283,15 +1292,14 @@
 		if (edge_port->txfifo.fifo) {
 			kfree(edge_port->txfifo.fifo);
 		}
+		port->active = 0;
+		port->open_count = 0;
 	}
 
 	MOD_DEC_USE_COUNT;
 	dbg(__FUNCTION__" exited");
 }   
 
-
-
-
 /*****************************************************************************
  * SerialWrite
  *	this function is called by the tty driver when data should be written to
@@ -1310,6 +1318,9 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	if (edge_port == NULL)
+		return -ENODEV;
+
 	// get a pointer to the Tx fifo
 	fifo = &edge_port->txfifo;
 
@@ -1399,7 +1410,6 @@
 	struct urb	*urb;
 	unsigned char	*buffer;
 	int		status;
-	unsigned long	flags;
 	int		count;
 	int		bytesleft;
 	int		firsthalf;
@@ -1407,13 +1417,9 @@
 
 	dbg(__FUNCTION__"(%d)", edge_port->port->number);
 
-	/* find our next free urb */	// ICK!!! FIXME!!!
-	save_flags(flags); cli();
-
 	if (edge_port->write_in_progress ||
 	    !edge_port->open             ||
 	    (fifo->count == 0)) {
-		restore_flags(flags);
 		dbg(__FUNCTION__"(%d) EXIT - fifo %d, PendingWrite = %d", edge_port->port->number, fifo->count, edge_port->write_in_progress);
 		return;
 	}
@@ -1426,14 +1432,12 @@
 	//	it's better to wait for more credits so we can do a larger
 	//	write.
 	if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) {
-		restore_flags(flags);
 		dbg(__FUNCTION__"(%d) Not enough credit - fifo %d TxCredit %d", edge_port->port->number, fifo->count, edge_port->txCredits );
 		return;
 	}
 
 	// lock this write
 	edge_port->write_in_progress = TRUE;
-	restore_flags(flags);
 
 	// get a pointer to the write_urb
 	urb = edge_port->write_urb;
@@ -1514,9 +1518,10 @@
 
 	dbg(__FUNCTION__);
 
-	if (edge_port->closePending == TRUE) {
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->closePending == TRUE)
 		return -ENODEV;
-	}
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
@@ -1549,6 +1554,11 @@
 
 	dbg(__FUNCTION__);
 
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->closePending == TRUE)
+		return -ENODEV;
+
 	if (!edge_port->open) {
 		dbg (__FUNCTION__" - port not opened");
 		return -EINVAL;
@@ -1576,6 +1586,9 @@
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
+	if (edge_port == NULL)
+		return;
+
 	if (!edge_port->open) {
 		dbg (__FUNCTION__" - port not opened");
 		return;
@@ -1618,6 +1631,9 @@
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
+	if (edge_port == NULL)
+		return;
+
 	if (!edge_port->open) {
 		dbg (__FUNCTION__" - port not opened");
 		return;
@@ -1675,6 +1691,9 @@
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
+	if (edge_port == NULL)
+		return;
+
 	if (!edge_port->open) {
 		dbg (__FUNCTION__" - port not opened");
 		return;
@@ -1833,7 +1852,6 @@
 	struct async_icount cnow;
 	struct async_icount cprev;
 	struct serial_icounter_struct icount;
-	unsigned long flags;
 
 
 	dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd);
@@ -1845,14 +1863,6 @@
 			return get_number_bytes_avail(edge_port, (unsigned int *) arg);
 			break;
 
-//		case TCGETS:		
-//			dbg(__FUNCTION__" (%d) TCGETS",  port->number);
-//			break;
-
-//		case TCSETS:		
-//			dbg(__FUNCTION__" (%d) TCSETS",  port->number);
-//			break;
-
 		case TIOCSERGETLSR:
 			dbg(__FUNCTION__" (%d) TIOCSERGETLSR",  port->number);
 			return get_lsr_info(edge_port, (unsigned int *) arg);
@@ -1878,17 +1888,13 @@
 
 		case TIOCMIWAIT:
 			dbg(__FUNCTION__" (%d) TIOCMIWAIT",  port->number);
-			save_flags(flags); cli();
 			cprev = edge_port->icount;
-			restore_flags(flags);
 			while (1) {
 				interruptible_sleep_on(&edge_port->delta_msr_wait);
 				/* see if a signal did it */
 				if (signal_pending(current))
 					return -ERESTARTSYS;
-				save_flags(flags); cli();
-				cnow = edge_port->icount; /* atomic copy */
-				restore_flags(flags);
+				cnow = edge_port->icount;
 				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
 				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
 					return -EIO; /* no change => error */
@@ -1904,9 +1910,7 @@
 			break;
 
 		case TIOCGICOUNT:
-			save_flags(flags); cli();
 			cnow = edge_port->icount;
-			restore_flags(flags);
 			icount.cts = cnow.cts;
 			icount.dsr = cnow.dsr;
 			icount.rng = cnow.rng;
@@ -2477,15 +2481,12 @@
 
 	/* Allocate our next urb */
 	urb = usb_alloc_urb (0);
+	if (!urb)
+		return -ENOMEM;
 
 	CmdUrbs++;
-
 	dbg(__FUNCTION__" - ALLOCATE URB %p (outstanding %d)", urb, CmdUrbs);
 
-	if (!urb) {
-		return -ENOMEM;
-	}
-
 	FILL_BULK_URB (urb, edge_serial->serial->dev, 
 		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
 		       buffer, length, edge_bulk_out_cmd_callback, edge_port);
@@ -2494,17 +2495,11 @@
 	urb->transfer_flags |= USB_QUEUE_BULK;
 
 	edge_port->commandPending = TRUE;
-	urb->dev = edge_serial->serial->dev;
 	status = usb_submit_urb(urb);
 
 	if (status) {
 		/* something went wrong */
 		dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
-
-		/* if this urb had a transfer buffer already (old transfer) free it */
-		if (urb->transfer_buffer != NULL) {
-			kfree(urb->transfer_buffer);
-		}
 		usb_unlink_urb (urb);
 		usb_free_urb   (urb);
 		return status;
@@ -2568,6 +2563,10 @@
 	MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, LCR, edge_port->shadowLCR);
 
 	status = write_cmd_usb(edge_port, cmdBuffer, cmdLen );
+	if (status) {
+		/* something bad happened, let's free up the memory */
+		kfree (cmdBuffer);
+	}
 
 	return status;
 }
@@ -2643,6 +2642,10 @@
 	MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->number, regNum, regValue);
 
 	status = write_cmd_usb(edge_port, cmdBuffer, cmdLen);
+	if (status) {
+		/* something bad happened, let's free up the memory */
+		kfree (cmdBuffer);
+	}
 
 	return status;
 }
@@ -2727,10 +2730,8 @@
 		unsigned char stop_char  = STOP_CHAR(tty);
 		unsigned char start_char = START_CHAR(tty);
 
-		{
-			send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
-			send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
-		}
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
 
 		/* if we are implementing INBOUND XON/XOFF */
 		if (I_IXOFF(tty)) {
@@ -2982,10 +2983,11 @@
 	get_product_info(edge_serial);
 
 	/* set the number of ports from the manufacturing description */
-	// FIXME  should we override this???
-	//serial->num_ports = serial->product_info.NumPorts;
+	/* serial->num_ports = serial->product_info.NumPorts; */
 	if (edge_serial->product_info.NumPorts != serial->num_ports) {
-		warn(__FUNCTION__ " - Device Reported %d serial ports vs core thinking we have %d ports, email greg@kroah.com this info.", edge_serial->product_info.NumPorts, serial->num_ports);
+		warn(__FUNCTION__ " - Device Reported %d serial ports vs core "
+		     "thinking we have %d ports, email greg@kroah.com this info.",
+		     edge_serial->product_info.NumPorts, serial->num_ports);
 	}
 
 	dbg(__FUNCTION__ " - time 1 %ld", jiffies);
@@ -3025,10 +3027,9 @@
 
 
 /****************************************************************************
- * usb_edgeport_disconnect
+ * edge_shutdown
  *	This function is called whenever the device is removed from the usb bus.
  ****************************************************************************/
-//static void usb_edgeport_disconnect (struct usb_device *dev, void *ptr)
 static void edge_shutdown (struct usb_serial *serial)
 {
 	int i;
@@ -3040,11 +3041,11 @@
 		while (serial->port[i].open_count > 0) {
 			edge_close (&serial->port[i], NULL);
 		}
+		kfree (serial->port[i].private);
+		serial->port[i].private = NULL;
 	}
-
-	/* free up any memory that we allocated */
-	// FIXME
-	
+	kfree (serial->private);
+	serial->private = NULL;
 }
 
 
@@ -3054,22 +3055,10 @@
  ****************************************************************************/
 int __init edgeport_init(void)
 {
-	usb_serial_register (&edgeport_4_device);
-	usb_serial_register (&rapidport_4_device);
-	usb_serial_register (&edgeport_4t_device);
-	usb_serial_register (&edgeport_2_device);
-	usb_serial_register (&edgeport_4i_device);
-	usb_serial_register (&edgeport_2i_device);
-	usb_serial_register (&edgeport_prl_device);
-	usb_serial_register (&edgeport_421_device);
-	usb_serial_register (&edgeport_21_device);
-	usb_serial_register (&edgeport_8dual_device);
-	usb_serial_register (&edgeport_8_device);
-	usb_serial_register (&edgeport_2din_device);
-	usb_serial_register (&edgeport_4din_device);
-	usb_serial_register (&edgeport_16dual_device);
-	usb_serial_register (&edgeport_compat_id_device);
-	usb_serial_register (&edgeport_8i_device);
+	usb_serial_register (&edgeport_1port_device);
+	usb_serial_register (&edgeport_2port_device);
+	usb_serial_register (&edgeport_4port_device);
+	usb_serial_register (&edgeport_8port_device);
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }
@@ -3082,22 +3071,10 @@
  ****************************************************************************/
 void __exit edgeport_exit (void)
 {
-	usb_serial_deregister (&edgeport_4_device);
-	usb_serial_deregister (&rapidport_4_device);
-	usb_serial_deregister (&edgeport_4t_device);
-	usb_serial_deregister (&edgeport_2_device);
-	usb_serial_deregister (&edgeport_4i_device);
-	usb_serial_deregister (&edgeport_2i_device);
-	usb_serial_deregister (&edgeport_prl_device);
-	usb_serial_deregister (&edgeport_421_device);
-	usb_serial_deregister (&edgeport_21_device);
-	usb_serial_deregister (&edgeport_8dual_device);
-	usb_serial_deregister (&edgeport_8_device);
-	usb_serial_deregister (&edgeport_2din_device);
-	usb_serial_deregister (&edgeport_4din_device);
-	usb_serial_deregister (&edgeport_16dual_device);
-	usb_serial_deregister (&edgeport_compat_id_device);
-	usb_serial_deregister (&edgeport_8i_device);
+	usb_serial_deregister (&edgeport_1port_device);
+	usb_serial_deregister (&edgeport_2port_device);
+	usb_serial_deregister (&edgeport_4port_device);
+	usb_serial_deregister (&edgeport_8port_device);
 }
 
 module_init(edgeport_init);

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