Subject: kern/28613: usb UPS's aren't uhids
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <wolfgang@wsrcc.com>
List: netbsd-bugs
Date: 12/12/2004 00:03:00
>Number:         28613
>Category:       kern
>Synopsis:       usb UPS's aren't uhids
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Dec 12 00:03:00 +0000 2004
>Originator:     Wolfgang S. Rupprecht
>Release:        NetBSD 2.99.11
>Organization:
W S Rupprecht Computer Consulting, Fremont CA
>Environment:
	
	
System: NetBSD capsicum.wsrcc.com 2.99.11 NetBSD 2.99.11 (WSRCC_ATHLON) #23: Sat Dec 11 14:14:27 PST 2004 wolfgang@capsicum.wsrcc.com:/var/obj/netbsd/sys/arch/i386/compile/WSRCC_ATHLON i386
Architecture: i386
Machine: i386
>Description:
	usb UPS's show up as usb uhid devices.  Apcupsd needs to see
	it as a ugen.  The simplest choice seems to be either this
	rude quirk-like hack.

>How-To-Repeat:
	
	compile and try to run:

	http://www.wsrcc.com/wolfgang/private/apcupsd-3.10.16-test2-wsr.tar.gz

>Fix:
	
The uhidev.c fix is absolutely needed. 	
	
The usbdi.c fixes are hail-mary's that looked wrong to me, but had no
effect on fixing a hang I saw when running apcupsd on VIA uhci's.
	
Index: uhidev.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhidev.c,v
retrieving revision 1.22
diff -u -r1.22 uhidev.c
--- uhidev.c	13 Sep 2004 12:55:49 -0000	1.22
+++ uhidev.c	11 Dec 2004 23:39:55 -0000
@@ -97,6 +97,11 @@
 	id = usbd_get_interface_descriptor(uaa->iface);
 	if (id == NULL || id->bInterfaceClass != UICLASS_HID)
 		return (UMATCH_NONE);
+
+	/* don't match APC products (all of them are UPS's) -wsr 2004/11/16 */
+	if (uaa->vendor == USB_VENDOR_APC)
+		return (UMATCH_NONE);
+
 	if (uaa->matchlvl)
 		return (uaa->matchlvl);
 	return (UMATCH_IFACECLASS_GENERIC);
Index: usbdi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.106
diff -u -r1.106 usbdi.c
--- usbdi.c	24 Oct 2004 12:52:40 -0000	1.106
+++ usbdi.c	11 Dec 2004 23:39:55 -0000
@@ -285,7 +285,7 @@
 	usb_dma_t *dmap = &xfer->dmabuf;
 	usbd_status err;
 	u_int size;
-	int s;
+	int s, sync;
 
 	DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%d, pipe=%p, running=%d\n",
 		    xfer, xfer->flags, pipe, pipe->running));
@@ -318,6 +318,10 @@
 	    !usbd_xfer_isread(xfer))
 		memcpy(KERNADDR(dmap, 0), xfer->buffer, size);
 
+	/* If the transfer is not synchronous, xfer may have been freed in a
+	 * callback before transfer returns, so check for synchronous now. */
+	sync = xfer->flags & USBD_SYNCHRONOUS ? 1 : 0;
+
 	err = pipe->methods->transfer(xfer);
 
 	if (err != USBD_IN_PROGRESS && err) {
@@ -330,7 +334,7 @@
 		}
 	}
 
-	if (!(xfer->flags & USBD_SYNCHRONOUS))
+	if (!sync)
 		return (err);
 
 	/* Sync transfer, wait for completion. */
@@ -340,7 +344,9 @@
 	if (!xfer->done) {
 		if (pipe->device->bus->use_polling)
 			panic("usbd_transfer: not done");
-		tsleep(xfer, PRIBIO, "usbsyn", 0);
+		/* hangs in ugen/apcupsd -wsr 2004/11/16 */
+		while (!xfer->done)
+		        tsleep(xfer, PRIBIO, "usbsyn", 0);
 	}
 	splx(s);
 	return (xfer->status);

>Unformatted: