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>
