Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Jan 2005 02:37:53 -0800
From:      Sandy Rutherford <sandy@krvarr.bc.ca>
To:        Julian Elischer <julian@elischer.org>
Cc:        freebsd-usb@freebsd.org
Subject:   Re: ulpt hangs on offline status
Message-ID:  <16872.62081.209945.743448@szamoca.krvarr.bc.ca>
In-Reply-To: <41E6D483.8050005@elischer.org>
References:  <16870.6275.128262.61361@szamoca.krvarr.bc.ca> <41E6D483.8050005@elischer.org>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Julian,

On Thu, 13 Jan 2005 you wrote:

 > Sandy Rutherford wrote:

 >> 
 >> [root@szamoca:14] usbdevs -v -d
 >> Controller /dev/usb0:
 >> addr 1: full speed, self powered, config 1, UHCI root hub(0x0000), Intel(0x0000), rev 1.00
 >> uhub0
 >> port 1 powered
 >> port 2 addr 2: full speed, power 98 mA, config 1, Centronics connector(0x0006), Entrega(0x1645), rev 1.00
 >> ulpt0
 >> 
 >> I am willing to muck around with the driver to try to fix this myself,
 >> but it would be useful to know if anybody else has seen or worked on
 >> this problem.
 >> 

 > not yet but I'm willing to believe that you may need to poll the device 
 > to see the change in status.
 > That would be handled in the "interrupt" type transfers..
 > We do not support them very well yet.

This evening, I threw a bunch of print statements into ulpt.c to see
what was happening.  This is for /sys/dev/usb/ulpt.c in FreeBSD 4.10.

As expected, it hangs trying to open the connection.

First it runs a tsleep loop:

	for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
		DPRINTF(("ulpt_open: waiting a while\n"));
		if (spin >= TIMEOUT) {
			error = EBUSY;
			sc->sc_state = 0;
			goto done;
		}

		/* wait 1/4 second, give up if we get a signal */
		error = tsleep(sc, LPTPRI | PCATCH, "ulptop", STEP);
		if (error != EWOULDBLOCK) {
			sc->sc_state = 0;
			goto done;
		}

		if (sc->sc_dying) {
			error = ENXIO;
			sc->sc_state = 0;
			goto done;
		}
	}

If the printer is offline, the tsleap returns an EAGAIN (resource
temporarily unavailable) error.  After the loop, it tries to open
input and output pipes.  If any of these fail, `error' is set to one
of EIO or ENOMEM and we `goto done'.

The problem is that if the printer comes back on line during the
tsleep loop, this is not caught and the tsleep loop exits with 
`error == EAGAIN'.  If subsequently, the input and output pipes are
opened successfully, `error' remains set to EAGAIN and this is what
`ulptopen' returns.  It should really return 0, because we have a good
connection and we should start writing data.

Therefore, I stuck the following just before the `done: ' tag:

	/* If we get to here with error == EAGAIN (resource temporarily */
	/* unavailable), it means open out and open in succeeded, even  */
        /* though the tsleep failed.  This probably means that          */
        /* the printer came online during the tsleep loop and we now    */ 
        /* have a connection.  Return 0 to start ulptwrite.             */
        /* --SR sandy@krvarr.bc.ca                                      */
	if (error ==  EAGAIN) {
	  DPRINTF(("error=%d.  Connection established?", error));
	  error = 0;
	}

 done:
	if (--sc->sc_refcnt < 0)
		usb_detach_wakeup(USBDEV(sc->sc_dev));

	DPRINTF(("ulptopen: done, error=%d\n", error));
	return (error);
}


It does the job for me.  ulpt now starts up when the printer comes
back online.

If anybody else has a similar problem, you might try this patch.  I'll
attach a proper patch file below.  If anybody does try this and it messes
something else up, please let me know.  USB devices are notoriously
flakey.

After testing this further for a few days, I'll send in a pr with the
patch.

BTW, I am running FreeBSD on i386 hardware.  The specifics of my USB
setup are:

usbdevs -v
Controller /dev/usb0:
addr 1: full speed, self powered, config 1, UHCI root hub(0x0000), Intel(0x0000), rev 1.00
 port 1 powered
 port 2 addr 2: full speed, power 98 mA, config 1, Centronics connector(0x0006), Entrega(0x1645), rev 1.00

Sandy

 
[-- Attachment #2 --]
*** ulpt.c.orig	Wed Jan 12 20:13:18 2005
--- ulpt.c	Sat Jan 15 01:52:00 2005
***************
*** 607,612 ****
--- 607,624 ----
  
  	sc->sc_state = ULPT_OPEN;
  
+ 
+ 	/* If we get to here with error == EAGAIN (resource temporarily */
+ 	/* unavailable), it means open out and open in succeeded, even  */
+         /* though the tsleep failed.  This probably means that          */
+         /* the printer came online during the tsleep loop and we now    */ 
+         /* have a connection.  Return 0 to start ulptwrite.             */
+         /* --SR sandy@krvarr.bc.ca                                      */
+ 	if (error ==  EAGAIN) {
+ 	  DPRINTF(("error=%d.  Connection established?", error));
+ 	  error = 0;
+ 	}
+ 
   done:
  	if (--sc->sc_refcnt < 0)
  		usb_detach_wakeup(USBDEV(sc->sc_dev));

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?16872.62081.209945.743448>