ChangeSet 1.1276.1.46, 2003/08/27 15:18:12-07:00, m@mbsks.franken.de

[PATCH] USB: Cyberjack patch

Mahlzeit

I attached you the diff for 2.6.0-test4. It does there also one program run
without any error, but not more. I hope this issue will be resolved soon,
but I do not know yet how.


 drivers/usb/serial/cyberjack.c |   66 +++++++++++++++++++++++++++++++----------
 1 files changed, 50 insertions(+), 16 deletions(-)


diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
--- a/drivers/usb/serial/cyberjack.c	Tue Sep  2 12:43:43 2003
+++ b/drivers/usb/serial/cyberjack.c	Tue Sep  2 12:43:43 2003
@@ -101,10 +101,11 @@
 };
 
 struct cyberjack_private {
-	short	rdtodo;		/* Bytes still to read */
+	spinlock_t	lock;		/* Lock for SMP */
+	short		rdtodo;		/* Bytes still to read */
 	unsigned char	wrbuf[5*64];	/* Buffer for collecting data to write */
-	short	wrfilled;	/* Overall data size we already got */
-	short	wrsent;		/* Data akready sent */
+	short		wrfilled;	/* Overall data size we already got */
+	short		wrsent;		/* Data akready sent */
 };
 
 /* do some startup allocations not currently performed by usb_serial_probe() */
@@ -120,6 +121,7 @@
 		return -ENOMEM;
 
 	/* set initial values */
+	spin_lock_init(&priv->lock);
 	priv->rdtodo = 0;
 	priv->wrfilled = 0;
 	priv->wrsent = 0;
@@ -146,6 +148,7 @@
 static int  cyberjack_open (struct usb_serial_port *port, struct file *filp)
 {
 	struct cyberjack_private *priv;
+	unsigned long flags;
 	int result = 0;
 
 	if (port_paranoia_check (port, __FUNCTION__))
@@ -160,9 +163,11 @@
 	port->tty->low_latency = 1;
 
 	priv = usb_get_serial_port_data(port);
+	spin_lock_irqsave(&priv->lock, flags);
 	priv->rdtodo = 0;
 	priv->wrfilled = 0;
 	priv->wrsent = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* shutdown any bulk reads that might be going on */
 	usb_unlink_urb (port->write_urb);
@@ -194,6 +199,7 @@
 {
 	struct usb_serial *serial = port->serial;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	int result;
 	int wrexpected;
 
@@ -210,15 +216,19 @@
 		return (0);
 	}
 
+	spin_lock_irqsave(&priv->lock, flags);
+
 	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
 		/* To much data  for buffer. Reset buffer. */
 		priv->wrfilled=0;
+		spin_unlock_irqrestore(&priv->lock, flags);
 		return (0);
 	}
 
 	/* Copy data */
 	if (from_user) {
 		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) {
+			spin_unlock_irqrestore(&priv->lock, flags);
 			return -EFAULT;
 		}
 	} else {
@@ -261,6 +271,7 @@
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled=0;
 			priv->wrsent=0;
+			spin_unlock_irqrestore(&priv->lock, flags);
 			return 0;
 		}
 
@@ -275,6 +286,8 @@
 		}
 	}
 
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	return (count);
 } 
 
@@ -282,8 +295,10 @@
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	struct usb_serial *serial;
 	unsigned char *data = urb->transfer_buffer;
+	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
@@ -302,21 +317,20 @@
 
 	/* React only to interrupts signaling a bulk_in transfer */
 	if( (urb->actual_length==4) && (data[0]==0x01) ) {
-		short old_rdtodo = priv->rdtodo;
+		short old_rdtodo;
 		int result;
 
 		/* This is a announcement of coming bulk_ins. */
 		unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
 
-		if( (size>259) || (size==0) ) {
-			dbg( "Bad announced bulk_in data length: %d", size );
-			/* Dunno what is most reliable to do here. */
-			/* return; */
-		}
+		spin_lock_irqsave(&priv->lock, flags);
+
+		old_rdtodo = priv->rdtodo;
 
 		if( (old_rdtodo+size)<(old_rdtodo) ) {
 			dbg( "To many bulk_in urbs to do." );
-			return;
+			spin_unlock_irqrestore(&priv->lock, flags);
+			goto resubmit;
 		}
 
 		/* "+=" is probably more fault tollerant than "=" */
@@ -324,23 +338,34 @@
 
 		dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo);
 
+		spin_unlock_irqrestore(&priv->lock, flags);
+
 		if( !old_rdtodo ) {
 			port->read_urb->dev = port->serial->dev;
-			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+			result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 			if( result )
 				err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 			dbg("%s - usb_submit_urb(read urb)", __FUNCTION__);
 		}
 	}
+
+resubmit:
+	port->interrupt_in_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (result)
+		err(" usb_submit_urb(read int) failed");
+	dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
 }
 
 static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
+	short todo;
 	int i;
 	int result;
 
@@ -372,18 +397,22 @@
 	  	tty_flip_buffer_push(tty);
 	}
 
+	spin_lock_irqsave(&priv->lock, flags);
+
 	/* Reduce urbs to do by one. */
 	priv->rdtodo-=urb->actual_length;
 	/* Just to be sure */
-	if ( priv->rdtodo<0 )
-		priv->rdtodo = 0;
+	if ( priv->rdtodo<0 ) priv->rdtodo = 0;
+	todo = priv->rdtodo;
 
-	dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	dbg("%s - rdtodo: %d", __FUNCTION__, todo);
 
 	/* Continue to read if we have still urbs to do. */
-	if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
+	if( todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
 		port->read_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result)
 			err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
 		dbg("%s - usb_submit_urb(read urb)", __FUNCTION__);
@@ -394,6 +423,7 @@
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -408,12 +438,15 @@
 		return;
 	}
 
+	spin_lock_irqsave(&priv->lock, flags);
+
 	/* only do something if we have more data to send */
 	if( priv->wrfilled ) {
 		int length, blksize, result;
 
 		if (port->write_urb->status == -EINPROGRESS) {
 			dbg("%s - already writing", __FUNCTION__);
+			spin_unlock_irqrestore(&priv->lock, flags);
 			return;
 		}
 
@@ -459,6 +492,7 @@
 	}
 
 exit:
+	spin_unlock_irqrestore(&priv->lock, flags);
 	schedule_work(&port->work);
 }
 
