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); }