Sorry, got the first one wrong
Hi,

after checking the new 2.6.8 code for drivers/usb/serial/cyberjack.c I
found some problems imho not properly taken care of.

I'm using a ASUS P2B-F board (i440BX chipset), a Cyberjack e-com USB
chipcard drive and a Debian kernel 2.6.8 (kernel-source-2.6.8 Version:
2.6.8-2); cyberjack.c there is unchanged from vanilla 2.6.8.1 from
kernel.org.

As far as I can remember the cyberjack didn't work since 2.6.0, but I
didn't look into all releases. When some problems got addressed in 2.6.7
I found that the changes made there just weren't enough to get my
cyberjack working (again under 2.6).

After some searching on newsgroups, this list, etc. I found
http://www.debianforum.de/forum/viewtopic.php?t=22954&start=15 (German
only) I think the patches mentioned there reverted too much, as I
experienced kernel debugging messages (enabled
CONFIG_DEBUG_SPINLOCK_SLEEP=y) to the effect of "sleeping function
called from invalid context" similar to the one mentioned later, but the
drive worked fine. Hooray!

Contacting the manufacturer (http://reiner-sct.de/) yielded 3 patches
via email (one of them against pre-2.6.7 versions), those described in
the provided URL seemed to derive from. I haven't found a direct link to
them up to this date. With these applied, the drive worked fine and no
more debugging messages showed up.

So, when looking into the new 2.6.8 driver I found that this version
(still/again) led to debugging messages like:

Debug: sleeping function called from invalid context at
arch/i386/lib/usercopy.c:623
in_atomic():1, irqs_disabled():1
[<c0107d9e>] dump_stack+0x1e/0x30
[<c011aa47>] __might_sleep+0xb7/0xe0
[<c01a7617>] copy_from_user+0x27/0x80
[<c8b57782>] cyberjack_write+0x432/0x4f0 [cyberjack]
[<c8b114c8>] serial_write+0x88/0xc0 [usbserial]
[<c01dc9d0>] write_chan+0x210/0x240
[<c01d71d8>] tty_write+0x1d8/0x270
[<c0159a7f>] vfs_write+0xcf/0x140
[<c0159bbb>] sys_write+0x4b/0x80
[<c0106fdb>] syscall_call+0x7/0xb

As the original patch to cyberjack.c (the third one was aimed at
usb-serial.c and could not be applied due to major changes there, which
seem to obsolete it anyway) didn't apply cleanly, I sort of wriggled it
in manually, resulting in the attached diff. This made the drive working
again with no more debugging messages relating to "sleeping functions...".

I hope someone more knowledgeable about kernel (usb) hacking than me
will find this information helpful for further improvement of the
driver. As I don't know what logs, config options etc. might shed
further light on this I didn't wan't to spam the list with lots of
perhaps unrelated/already known details. If You need something specific,
feel free to contact me.

        Regards,
        Klaus Hörcher



--- kernel-source-2.6.8.orig/drivers/usb/serial/cyberjack.c	2004-08-14 07:37:41.000000000 +0200
+++ kernel-source-2.6.8/drivers/usb/serial/cyberjack.c	2004-08-23 11:32:53.000000000 +0200
@@ -44,7 +44,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0"
+#define DRIVER_VERSION "v1.01"
 #define DRIVER_AUTHOR "Matthias Bruestle"
 #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver"
 
@@ -111,6 +111,7 @@
 static int cyberjack_startup (struct usb_serial *serial)
 {
 	struct cyberjack_private *priv;
+	int i;
 
 	dbg("%s", __FUNCTION__);
 
@@ -128,6 +129,16 @@
 
 	init_waitqueue_head(&serial->port[0]->write_wait);
 
+	for (i = 0; i < serial->num_ports; ++i) {
+		int result;
+		serial->port[i]->interrupt_in_urb->dev = serial->dev;
+		result = usb_submit_urb(serial->port[i]->interrupt_in_urb, 
+					GFP_KERNEL);
+		if (result)
+			err(" usb_submit_urb(read int) failed");
+		dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
+	}
+
 	return( 0 );
 }
 
@@ -138,6 +149,7 @@
 	dbg("%s", __FUNCTION__);
 
 	for (i=0; i < serial->num_ports; ++i) {
+		usb_unlink_urb (serial->port[i]->interrupt_in_urb);
 		/* My special items, the standard routines free my urbs */
 		kfree(usb_get_serial_port_data(serial->port[i]));
 		usb_set_serial_port_data(serial->port[i], NULL);
@@ -168,17 +180,6 @@
 	priv->wrsent = 0;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* shutdown any bulk reads that might be going on */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	usb_unlink_urb (port->interrupt_in_urb);
-
-	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__);
-
 	return result;
 }
 
@@ -190,11 +191,6 @@
 		/* shutdown any bulk reads that might be going on */
 		usb_unlink_urb (port->write_urb);
 		usb_unlink_urb (port->read_urb);
-		usb_unlink_urb (port->interrupt_in_urb);
-		dbg("%s - usb_clear_halt", __FUNCTION__ );
-		usb_clear_halt(port->serial->dev, port->write_urb->pipe);
-		usb_clear_halt(port->serial->dev, port->read_urb->pipe);
-		usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe);
 	}
 }
 
@@ -205,6 +201,7 @@
 	unsigned long flags;
 	int result;
 	int wrexpected;
+	unsigned char localbuf[CYBERJACK_LOCAL_BUF_SIZE];	/* Buffer for collecting data to write */
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - from_user %d", __FUNCTION__, from_user);
@@ -221,23 +218,30 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
+	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ||
+		(count>sizeof(localbuf)) ) {
 		/* To much data for buffer. Reset buffer. */
 		priv->wrfilled=0;
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return (0);
 	}
 
+	spin_unlock_irqrestore(&priv->lock, flags);
+	
+	
 	/* Copy data */
 	if (from_user) {
-		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) {
-			spin_unlock_irqrestore(&priv->lock, flags);
+		if (copy_from_user(localbuf, buf, count)) {
 			return -EFAULT;
 		}
 	} else {
-		memcpy (priv->wrbuf+priv->wrfilled, buf, count);
+		memcpy (localbuf, buf, count);
 	}  
 
+	spin_lock_irqsave(&priv->lock, flags);
+
+	memcpy (priv->wrbuf+priv->wrfilled, localbuf, count);
+	
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
 		priv->wrbuf+priv->wrfilled);
 	priv->wrfilled += count;
@@ -376,6 +380,10 @@
 	}
 
 	tty = port->tty;
+	if (!tty) {
+		dbg("%s - ignoring since device not open\n", __FUNCTION__);
+		return;
+	}
 	if (urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
 			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */


Reply via email to