usb/110856: ugen: interrupt in msgs are truncated when buffer is full

Markus Henschel m.henschel at bally-wulff.de
Mon Mar 26 14:30:13 UTC 2007


>Number:         110856
>Category:       usb
>Synopsis:       ugen: interrupt in msgs are truncated when buffer is full
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-usb
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Mar 26 14:30:13 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Markus Henschel
>Release:        6.2 custom kernel
>Organization:
Bally Wulff Automaten GmbH
>Environment:
FreeBSD freebsd-1.bally.de 6.2-RELEASE FreeBSD 6.2-RELEASE #11: Fri Mar 23 21:28:38 CET 2007     prog at freebsd-1.bally.de:/usr/obj/usr/src/sys/BALLYWULFF  i386
>Description:
We use ugen for some user space drivers. When an interrupt in endpoint is used ugen creates a queue that is filled by the kernel. The user space driver is responsible for reading data from the device file. If this happens too slow the queue is full and new msgs arriving from the usb device are lost. This behavior is OK. 

The problem is that the queue is not a multiple of the interrupt in endpoints msgs size. So it is possible that the last msg in the queue is truncated. This is very hard to detect for a user space driver. The data stream seen by the user space driver will contain an incomplete msgs directly followed by the next message without knowing truncation happened (except when using some data corruption detection mechanism).

It would be much better if ugen would fill the queues of interrupt in endpoints until there is no more space for a complete msg. This way the user space driver will not loose sync with the incoming msgs. 
>How-To-Repeat:
1. Attach a device served by the ugen driver
2. Open an interrupt in endpoint
3. read data in chunk equivalent to the endpoints msg size
4. pause the reading to fill the ugen kernel msg queue
5. resume reading chunks, the last chunk that comes from the queue will probably be truncated directly followed by the next new chunk

(tested with a msgs size of the interrupt in endpoint of 16)

>Fix:
I use the attached patch in our company and it works as expected.

Patch attached with submission follows:

--- /usr/src/sys/dev/usb/ugen.c.old	Mon Mar 26 15:56:18 2007
+++ /usr/src/sys/dev/usb/ugen.c	Fri Mar 23 21:27:13 2007
@@ -1081,6 +1081,7 @@
 	/*struct ugen_softc *sc = sce->sc;*/
 	u_int32_t count;
 	u_char *ibuf;
+	int iSize;
 
 	if (status == USBD_CANCELLED)
 		return;
@@ -1100,6 +1101,10 @@
 	DPRINTFN(5, ("          data = %02x %02x %02x\n",
 		     ibuf[0], ibuf[1], ibuf[2]));
 
+	// begin changes MH at BW
+	iSize = UGETW(sce->edesc->wMaxPacketSize);
+	if (count <= ( (UGEN_IBSIZE/iSize)*iSize - sce->q.c_cc))
+	// end changes MH at BW
 	(void)b_to_q(ibuf, count, &sce->q);
 
 	if (sce->state & UGEN_ASLP) {

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-usb mailing list