Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Apr 2002 12:56:30 -0700
From:      Peter Haight <peterh@sapros.com>
To:        Nick Hibma <n_hibma@van-laarhoven.org>
Cc:        hardware@freebsd.org
Subject:   Re: Reading from the USB ugen device. 
Message-ID:  <200204151956.g3FJuURg037596@wartch.sapros.com>

next in thread | raw e-mail | index | archive | help
>> Ok. But why does this happen:
>>
>> read(3, 0x8091800, 1024)
>> read -1 bytes
>
>If you print the errno at that point I can tell you. But probably the
>errno is ETIMEDOUT, which means that the device told us that there is
>no data, so it NACKed the transfer until we got bored.

Actually, I'm getting an EIO here.

>> At that same point in the protocol if I do:
>> read(3, 0x8091800, 64)
>> read 64 bytes
>>
>> I would expect:
>> read(3, 0x8091800, 1024)
>> read 64 bytes
>
>I don't know why it reads 64 instead of 1024 bytes. Most probably the
>author of the program assumes that he has to do the chunking that is
>automatically done by the uhci controller driver. Or maybe I
>misunderstood your question.

Yeah. I don't think I'm being clear. What's going on at this point is that
the program is requesting a bunch of information from the palm pilot about
what's on it. These are all very short bulk data transfers. Each set goes
like this:

write(/dev/ugen0.2, header, 6) (length of next write is in header)
write(/dev/ugen0.2, data, 8)
read(/dev/ugen0.2, header, 6)
read(/dev/ugen0.2, data, 62) (length of this read is read from header)

I'll call the 'expected read length' the length I read from the header, not
the argument I pass to read(). I'll call the argument I pass to read
'requested read length'.

The wierd thing is that if 'expected read length' = 'requested read length'
everything works fine, but if 'expected read length' = 64 and 'requested
read length' = 1024, it hangs and eventually I get a EIO.

I would expect that if I have SHORT_XFER set on /dev/ugen0.2, then I could
always set my 'requested read length' to 1024 (i.e. read(/dev/ugen0.2,
buffer, 1024)) and that should just always return a buffer that is as long
as whatever is read from the bus. (Let's ignore the case where the amount of
data is bigger than 1024. That isn't happening. These are all very small
amounts of data.)

I'll stick the function that I'm using to do the read on the end of this
email. Someone else wrote this function and it wasn't working for me as you
see it below. To get it to work, I had to change the line: 
u->iobuflen = read(p->fd, u->iobufp, 1024);
to:
u->iobuflen = read(p->fd, u->iobufp, len);

len is the expected read length.

This makes no sense to me. I think it should work with the original
function.

Thanks for putting up with my inability to explain my problem clearly.

static int
usb_read(PConnection *p, unsigned char *buf, int len)
{
	/*
	 *  We've got to do intermediate buffering of the USB data
	 *  from the Visor's bulk endpoint.  This is because the kernel
	 *  USB driver isn't buffering any data, and we must have a read
	 *  operation pending at least as large as the USB transfer size
	 *  might potentially be.  
	 *
	 *  Here, we use a 1024 byte buffer, and return data out of
	 *  it.  This could return "short" reads to the caller, but
	 *  isn't semantically any different than reading an TTY device
	 *  which won't return a necessarily predicatable amount of
	 *  data.
	 */

	struct usb_data *u = p->io_private;
	int copy_len, retlen = 0;

	do {
		/* (?) Return leftover stuff from the previous read.
		 */
		if (u->iobuflen > 0) {
			copy_len = (len > u->iobuflen) ? u->iobuflen : len;

			memcpy(buf, u->iobufp, copy_len);
				/* XXX - Potential buffer overflow? */
			u->iobufp += copy_len;
			u->iobuflen -= copy_len;
			buf += copy_len;
			len -= copy_len;
			retlen += copy_len;
		}

		if (retlen == 0) {
			/* (?) There wasn't anything left over from the
			 * last read(). Read some new stuff.
			 */
			if (u->iobuflen > 0) {
				fprintf(stderr,
					_("usb: trying to fill a non-empty "
					  "buffer.\n"));
				abort();
			}

			u->iobufp = u->iobuf;
			u->iobuflen = read(p->fd, u->iobufp, 1024);
			if (u->iobuflen < 0) {
				perror("usb read");
				return u->iobuflen;
			}
		}
	} while (retlen == 0);

	return retlen;
}



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hardware" in the body of the message




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