[Midnightbsd-cvs] src [6568] trunk/sys/dev/usb: Update USB stack

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Dec 28 10:28:47 EST 2013


Revision: 6568
          http://svnweb.midnightbsd.org/src/?rev=6568
Author:   laffer1
Date:     2013-12-28 10:28:46 -0500 (Sat, 28 Dec 2013)
Log Message:
-----------
Update USB stack

Obtained from: FreeBSD 9.2

Modified Paths:
--------------
    trunk/sys/dev/usb/input/atp.c
    trunk/sys/dev/usb/input/uep.c
    trunk/sys/dev/usb/input/uhid.c
    trunk/sys/dev/usb/input/ukbd.c
    trunk/sys/dev/usb/input/ums.c
    trunk/sys/dev/usb/misc/udbp.c
    trunk/sys/dev/usb/net/if_aue.c
    trunk/sys/dev/usb/net/if_axe.c
    trunk/sys/dev/usb/net/if_cdce.c
    trunk/sys/dev/usb/net/if_cue.c
    trunk/sys/dev/usb/net/if_ipheth.c
    trunk/sys/dev/usb/net/if_kue.c
    trunk/sys/dev/usb/net/if_mos.c
    trunk/sys/dev/usb/net/if_rue.c
    trunk/sys/dev/usb/net/if_udav.c
    trunk/sys/dev/usb/net/if_udavreg.h
    trunk/sys/dev/usb/net/if_usie.c
    trunk/sys/dev/usb/net/uhso.c
    trunk/sys/dev/usb/net/usb_ethernet.c
    trunk/sys/dev/usb/quirk/usb_quirk.c
    trunk/sys/dev/usb/quirk/usb_quirk.h
    trunk/sys/dev/usb/serial/u3g.c
    trunk/sys/dev/usb/serial/uark.c
    trunk/sys/dev/usb/serial/ubsa.c
    trunk/sys/dev/usb/serial/ubser.c
    trunk/sys/dev/usb/serial/uchcom.c
    trunk/sys/dev/usb/serial/ucycom.c
    trunk/sys/dev/usb/serial/ufoma.c
    trunk/sys/dev/usb/serial/uftdi.c
    trunk/sys/dev/usb/serial/uftdi_reg.h
    trunk/sys/dev/usb/serial/ugensa.c
    trunk/sys/dev/usb/serial/uipaq.c
    trunk/sys/dev/usb/serial/ulpt.c
    trunk/sys/dev/usb/serial/umcs.c
    trunk/sys/dev/usb/serial/umct.c
    trunk/sys/dev/usb/serial/umodem.c
    trunk/sys/dev/usb/serial/umoscom.c
    trunk/sys/dev/usb/serial/uplcom.c
    trunk/sys/dev/usb/serial/usb_serial.c
    trunk/sys/dev/usb/serial/usb_serial.h
    trunk/sys/dev/usb/serial/uslcom.c
    trunk/sys/dev/usb/serial/uvisor.c
    trunk/sys/dev/usb/serial/uvscom.c
    trunk/sys/dev/usb/storage/umass.c
    trunk/sys/dev/usb/storage/urio.c
    trunk/sys/dev/usb/template/usb_template.c
    trunk/sys/dev/usb/wlan/if_rum.c
    trunk/sys/dev/usb/wlan/if_run.c
    trunk/sys/dev/usb/wlan/if_uath.c
    trunk/sys/dev/usb/wlan/if_upgt.c
    trunk/sys/dev/usb/wlan/if_upgtvar.h
    trunk/sys/dev/usb/wlan/if_ural.c
    trunk/sys/dev/usb/wlan/if_urtw.c
    trunk/sys/dev/usb/wlan/if_zyd.c

Modified: trunk/sys/dev/usb/input/atp.c
===================================================================
--- trunk/sys/dev/usb/input/atp.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/input/atp.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -114,7 +114,7 @@
 
 
 /* Tunables */
-SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB atp");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB atp");
 
 #ifdef USB_DEBUG
 enum atp_log_level {

Modified: trunk/sys/dev/usb/input/uep.c
===================================================================
--- trunk/sys/dev/usb/input/uep.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/input/uep.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -57,7 +57,7 @@
 #ifdef USB_DEBUG
 static int uep_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW, 0, "USB uep");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW, 0, "USB uep");
 SYSCTL_INT(_hw_usb_uep, OID_AUTO, debug, CTLFLAG_RW,
     &uep_debug, 0, "Debug level");
 #endif

Modified: trunk/sys/dev/usb/input/uhid.c
===================================================================
--- trunk/sys/dev/usb/input/uhid.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/input/uhid.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -78,7 +78,7 @@
 #ifdef USB_DEBUG
 static int uhid_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uhid, CTLFLAG_RW, 0, "USB uhid");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uhid, CTLFLAG_RW, 0, "USB uhid");
 SYSCTL_INT(_hw_usb_uhid, OID_AUTO, debug, CTLFLAG_RW,
     &uhid_debug, 0, "Debug level");
 #endif
@@ -691,10 +691,11 @@
 	 */
 	if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
 	    (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
-	    ((uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD) ||
-	     (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))) {
+	    (((uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD) &&
+	      !usb_test_quirk(uaa, UQ_KBD_IGNORE)) ||
+	     ((uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) &&
+	      !usb_test_quirk(uaa, UQ_UMS_IGNORE))))
 		return (ENXIO);
-	}
 
 	return (BUS_PROBE_GENERIC);
 }

Modified: trunk/sys/dev/usb/input/ukbd.c
===================================================================
--- trunk/sys/dev/usb/input/ukbd.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/input/ukbd.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -93,13 +93,12 @@
 static int ukbd_debug = 0;
 static int ukbd_no_leds = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd");
-SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd");
+SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &ukbd_debug, 0, "Debug level");
-SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RW,
+TUNABLE_INT("hw.usb.ukbd.debug", &ukbd_debug);
+SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RW | CTLFLAG_TUN,
     &ukbd_no_leds, 0, "Disables setting of keyboard leds");
-
-TUNABLE_INT("hw.usb.ukbd.debug", &ukbd_debug);
 TUNABLE_INT("hw.usb.ukbd.no_leds", &ukbd_no_leds);
 #endif
 
@@ -996,13 +995,12 @@
 	if (uaa->info.bInterfaceClass != UICLASS_HID)
 		return (ENXIO);
 
+	if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
+		return (ENXIO);
+
 	if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
-	    (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD)) {
-		if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
-			return (ENXIO);
-		else
-			return (BUS_PROBE_DEFAULT);
-	}
+	    (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD))
+		return (BUS_PROBE_DEFAULT);
 
 	error = usbd_req_get_hid_desc(uaa->device, NULL,
 	    &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
@@ -1010,23 +1008,20 @@
 	if (error)
 		return (ENXIO);
 
-	/*
-	 * NOTE: we currently don't support USB mouse and USB keyboard
-	 * on the same USB endpoint.
-	 */
-	if (hid_is_collection(d_ptr, d_len,
-	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) {
-		/* most likely a mouse */
-		error = ENXIO;
-	} else if (hid_is_collection(d_ptr, d_len,
-	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) {
-		if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
+	if (hid_is_keyboard(d_ptr, d_len)) {
+		if (hid_is_mouse(d_ptr, d_len)) {
+			/*
+			 * NOTE: We currently don't support USB mouse
+			 * and USB keyboard on the same USB endpoint.
+			 * Let "ums" driver win.
+			 */
 			error = ENXIO;
-		else
+		} else {
 			error = BUS_PROBE_DEFAULT;
-	} else
+		}
+	} else {
 		error = ENXIO;
-
+	}
 	free(d_ptr, M_TEMP);
 	return (error);
 }

Modified: trunk/sys/dev/usb/input/ums.c
===================================================================
--- trunk/sys/dev/usb/input/ums.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/input/ums.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -76,7 +76,7 @@
 #ifdef USB_DEBUG
 static int ums_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums");
 SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, CTLFLAG_RW,
     &ums_debug, 0, "Debug level");
 #endif
@@ -368,9 +368,7 @@
 {
 	struct usb_attach_arg *uaa = device_get_ivars(dev);
 	void *d_ptr;
-	struct hid_data *hd;
-	struct hid_item hi;
-	int error, mdepth, found;
+	int error;
 	uint16_t d_len;
 
 	DPRINTFN(11, "\n");
@@ -381,6 +379,9 @@
 	if (uaa->info.bInterfaceClass != UICLASS_HID)
 		return (ENXIO);
 
+	if (usb_test_quirk(uaa, UQ_UMS_IGNORE))
+		return (ENXIO);
+
 	if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
 	    (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))
 		return (BUS_PROBE_DEFAULT);
@@ -391,44 +392,13 @@
 	if (error)
 		return (ENXIO);
 
-	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
-	if (hd == NULL)
-		return (0);
-	mdepth = 0;
-	found = 0;
-	while (hid_get_item(hd, &hi)) {
-		switch (hi.kind) {
-		case hid_collection:
-			if (mdepth != 0)
-				mdepth++;
-			else if (hi.collection == 1 &&
-			     hi.usage ==
-			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
-				mdepth++;
-			break;
-		case hid_endcollection:
-			if (mdepth != 0)
-				mdepth--;
-			break;
-		case hid_input:
-			if (mdepth == 0)
-				break;
-			if (hi.usage ==
-			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
-			    (hi.flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
-				found++;
-			if (hi.usage ==
-			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
-			    (hi.flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
-				found++;
-			break;
-		default:
-			break;
-		}
-	}
-	hid_end_parse(hd);
+	if (hid_is_mouse(d_ptr, d_len))
+		error = BUS_PROBE_DEFAULT;
+	else
+		error = ENXIO;
+
 	free(d_ptr, M_TEMP);
-	return (found ? BUS_PROBE_DEFAULT : ENXIO);
+	return (error);
 }
 
 static void

Modified: trunk/sys/dev/usb/misc/udbp.c
===================================================================
--- trunk/sys/dev/usb/misc/udbp.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/misc/udbp.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -96,7 +96,7 @@
 #ifdef USB_DEBUG
 static int udbp_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp");
 SYSCTL_INT(_hw_usb_udbp, OID_AUTO, debug, CTLFLAG_RW,
     &udbp_debug, 0, "udbp debug level");
 #endif
@@ -410,12 +410,12 @@
 
 		/* allocate new mbuf */
 
-		MGETHDR(m, M_DONTWAIT, MT_DATA);
+		MGETHDR(m, M_NOWAIT, MT_DATA);
 
 		if (m == NULL) {
 			goto tr_setup;
 		}
-		MCLGET(m, M_DONTWAIT);
+		MCLGET(m, M_NOWAIT);
 
 		if (!(m->m_flags & M_EXT)) {
 			m_freem(m);

Modified: trunk/sys/dev/usb/net/if_aue.c
===================================================================
--- trunk/sys/dev/usb/net/if_aue.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_aue.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -102,7 +102,7 @@
 #ifdef USB_DEBUG
 static int aue_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, aue, CTLFLAG_RW, 0, "USB aue");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, aue, CTLFLAG_RW, 0, "USB aue");
 SYSCTL_INT(_hw_usb_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0,
     "Debug level");
 #endif

Modified: trunk/sys/dev/usb/net/if_axe.c
===================================================================
--- trunk/sys/dev/usb/net/if_axe.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_axe.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -133,7 +133,7 @@
 #ifdef USB_DEBUG
 static int axe_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe");
 SYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0,
     "Debug level");
 #endif
@@ -162,6 +162,7 @@
 	AXE_DEV(GOODWAY, GWUSB2E, 0),
 	AXE_DEV(IODATA, ETGUS2, AXE_FLAG_178),
 	AXE_DEV(JVC, MP_PRX1, 0),
+	AXE_DEV(LENOVO, ETHERNET, AXE_FLAG_772B),
 	AXE_DEV(LINKSYS2, USB200M, 0),
 	AXE_DEV(LINKSYS4, USB1000, AXE_FLAG_178),
 	AXE_DEV(LOGITEC, LAN_GTJU2A, AXE_FLAG_178),
@@ -1114,7 +1115,7 @@
 		return (EINVAL);
 	}
 
-	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	if (m == NULL) {
 		ifp->if_iqdrops++;
 		return (ENOMEM);
@@ -1354,15 +1355,14 @@
 
 	if (AXE_IS_178_FAMILY(sc)) {
 		sc->sc_flags &= ~(AXE_FLAG_STD_FRAME | AXE_FLAG_CSUM_FRAME);
-		if ((sc->sc_flags & AXE_FLAG_772B) != 0)
+		if ((sc->sc_flags & AXE_FLAG_772B) != 0 &&
+		    (ifp->if_capenable & IFCAP_RXCSUM) != 0) {
 			sc->sc_lenmask = AXE_CSUM_HDR_LEN_MASK;
-		else
+			sc->sc_flags |= AXE_FLAG_CSUM_FRAME;
+		} else {
 			sc->sc_lenmask = AXE_HDR_LEN_MASK;
-		if ((sc->sc_flags & AXE_FLAG_772B) != 0 &&
-		    (ifp->if_capenable & IFCAP_RXCSUM) != 0)
-			sc->sc_flags |= AXE_FLAG_CSUM_FRAME;
-		else
 			sc->sc_flags |= AXE_FLAG_STD_FRAME;
+		}
 	}
 
 	/* Configure TX/RX checksum offloading. */

Modified: trunk/sys/dev/usb/net/if_cdce.c
===================================================================
--- trunk/sys/dev/usb/net/if_cdce.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_cdce.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -111,7 +111,7 @@
 static int cdce_debug = 0;
 static int cdce_tx_interval = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet");
 SYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0,
     "Debug level");
 SYSCTL_INT(_hw_usb_cdce, OID_AUTO, interval, CTLFLAG_RW, &cdce_tx_interval, 0,
@@ -500,6 +500,7 @@
 	const struct usb_interface_descriptor *id;
 	const struct usb_cdc_ethernet_descriptor *ued;
 	const struct usb_config *pcfg;
+	uint32_t seed;
 	int error;
 	uint8_t i;
 	uint8_t data_iface_no;
@@ -612,8 +613,9 @@
 		/* fake MAC address */
 
 		device_printf(dev, "faking MAC address\n");
+		seed = ticks;
 		sc->sc_ue.ue_eaddr[0] = 0x2a;
-		memcpy(&sc->sc_ue.ue_eaddr[1], &ticks, sizeof(uint32_t));
+		memcpy(&sc->sc_ue.ue_eaddr[1], &seed, sizeof(uint32_t));
 		sc->sc_ue.ue_eaddr[5] = device_get_unit(dev);
 
 	} else {
@@ -753,7 +755,7 @@
 				}
 			}
 			if (m->m_len != m->m_pkthdr.len) {
-				mt = m_defrag(m, M_DONTWAIT);
+				mt = m_defrag(m, M_NOWAIT);
 				if (mt == NULL) {
 					m_freem(m);
 					ifp->if_oerrors++;
@@ -1369,9 +1371,9 @@
 				/* silently ignore this frame */
 				continue;
 			} else if (temp > (int)(MHLEN - ETHER_ALIGN)) {
-				m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+				m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 			} else {
-				m = m_gethdr(M_DONTWAIT, MT_DATA);
+				m = m_gethdr(M_NOWAIT, MT_DATA);
 			}
 
 			DPRINTFN(16, "frame %u, offset = %u, length = %u \n",

Modified: trunk/sys/dev/usb/net/if_cue.c
===================================================================
--- trunk/sys/dev/usb/net/if_cue.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_cue.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -124,7 +124,7 @@
 #ifdef USB_DEBUG
 static int cue_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue");
 SYSCTL_INT(_hw_usb_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0,
     "Debug level");
 #endif

Modified: trunk/sys/dev/usb/net/if_ipheth.c
===================================================================
--- trunk/sys/dev/usb/net/if_ipheth.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_ipheth.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -81,7 +81,7 @@
 #ifdef USB_DEBUG
 static int ipheth_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet");
 SYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RW, &ipheth_debug, 0, "Debug level");
 #endif
 
@@ -161,6 +161,12 @@
 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4,
 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
 	    IPHETH_USBINTF_PROTO)},
+	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4S,
+	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+	    IPHETH_USBINTF_PROTO)},
+	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_5,
+	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+	    IPHETH_USBINTF_PROTO)},
 };
 
 static int

Modified: trunk/sys/dev/usb/net/if_kue.c
===================================================================
--- trunk/sys/dev/usb/net/if_kue.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_kue.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -165,7 +165,7 @@
 #ifdef USB_DEBUG
 static int kue_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, kue, CTLFLAG_RW, 0, "USB kue");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, kue, CTLFLAG_RW, 0, "USB kue");
 SYSCTL_INT(_hw_usb_kue, OID_AUTO, debug, CTLFLAG_RW, &kue_debug, 0,
     "Debug level");
 #endif

Modified: trunk/sys/dev/usb/net/if_mos.c
===================================================================
--- trunk/sys/dev/usb/net/if_mos.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_mos.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -132,7 +132,7 @@
 #ifdef USB_DEBUG
 static int mos_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW, 0, "USB mos");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW, 0, "USB mos");
 SYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0,
     "Debug level");
 #endif

Modified: trunk/sys/dev/usb/net/if_rue.c
===================================================================
--- trunk/sys/dev/usb/net/if_rue.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_rue.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -99,7 +99,7 @@
 #ifdef USB_DEBUG
 static int rue_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue");
 SYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW,
     &rue_debug, 0, "Debug level");
 #endif

Modified: trunk/sys/dev/usb/net/if_udav.c
===================================================================
--- trunk/sys/dev/usb/net/if_udav.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_udav.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -181,10 +181,19 @@
 	.ue_mii_sts = udav_ifmedia_status,
 };
 
+static const struct usb_ether_methods udav_ue_methods_nophy = {
+	.ue_attach_post = udav_attach_post,
+	.ue_start = udav_start,
+	.ue_init = udav_init,
+	.ue_stop = udav_stop,
+	.ue_setmulti = udav_setmulti,
+	.ue_setpromisc = udav_setpromisc,
+};
+
 #ifdef USB_DEBUG
 static int udav_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav");
 SYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
     "Debug level");
 #endif
@@ -206,7 +215,8 @@
 	{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515, 0)},
 	/* Kontron AG USB Ethernet */
 	{USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_DM9601, 0)},
-	{USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_JP1082, 0)},
+	{USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_JP1082,
+	    UDAV_FLAG_NO_PHY)},
 };
 
 static void
@@ -259,11 +269,20 @@
 		goto detach;
 	}
 
+	/*
+	 * The JP1082 has an unusable PHY and provides no link information.
+	 */
+	if (sc->sc_flags & UDAV_FLAG_NO_PHY) {
+		ue->ue_methods = &udav_ue_methods_nophy;
+		sc->sc_flags |= UDAV_FLAG_LINK;
+	} else {
+		ue->ue_methods = &udav_ue_methods;
+	}
+
 	ue->ue_sc = sc;
 	ue->ue_dev = dev;
 	ue->ue_udev = uaa->device;
 	ue->ue_mtx = &sc->sc_mtx;
-	ue->ue_methods = &udav_ue_methods;
 
 	error = uether_ifattach(ue);
 	if (error) {
@@ -712,7 +731,8 @@
 	UDAV_LOCK_ASSERT(sc, MA_OWNED);
 
 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
-	sc->sc_flags &= ~UDAV_FLAG_LINK;
+	if (!(sc->sc_flags & UDAV_FLAG_NO_PHY))
+		sc->sc_flags &= ~UDAV_FLAG_LINK;
 
 	/*
 	 * stop all the transfers, if not already stopped:

Modified: trunk/sys/dev/usb/net/if_udavreg.h
===================================================================
--- trunk/sys/dev/usb/net/if_udavreg.h	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_udavreg.h	2013-12-28 15:28:46 UTC (rev 6568)
@@ -159,6 +159,7 @@
 	int			sc_flags;
 #define	UDAV_FLAG_LINK		0x0001
 #define	UDAV_FLAG_EXT_PHY	0x0040
+#define	UDAV_FLAG_NO_PHY	0x0080
 };
 
 #define	UDAV_LOCK(_sc)			mtx_lock(&(_sc)->sc_mtx)

Modified: trunk/sys/dev/usb/net/if_usie.c
===================================================================
--- trunk/sys/dev/usb/net/if_usie.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/if_usie.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -77,7 +77,7 @@
 #ifdef	USB_DEBUG
 static int usie_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, usie, CTLFLAG_RW, 0, "sierra USB modem");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, usie, CTLFLAG_RW, 0, "sierra USB modem");
 SYSCTL_INT(_hw_usb_usie, OID_AUTO, debug, CTLFLAG_RW, &usie_debug, 0,
     "usie debug level");
 #endif
@@ -95,7 +95,9 @@
 static device_probe_t usie_probe;
 static device_attach_t usie_attach;
 static device_detach_t usie_detach;
+static void usie_free_softc(struct usie_softc *);
 
+static void usie_free(struct ucom_softc *);
 static void usie_uc_update_line_state(struct ucom_softc *, uint8_t);
 static void usie_uc_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
 static void usie_uc_cfg_set_dtr(struct ucom_softc *, uint8_t);
@@ -189,7 +191,7 @@
 	DEVMETHOD(device_probe, usie_probe),
 	DEVMETHOD(device_attach, usie_attach),
 	DEVMETHOD(device_detach, usie_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static driver_t usie_driver = {
@@ -216,6 +218,7 @@
 	.ucom_stop_read = &usie_uc_stop_read,
 	.ucom_start_write = &usie_uc_start_write,
 	.ucom_stop_write = &usie_uc_stop_write,
+	.ucom_free = &usie_free,
 };
 
 static void
@@ -298,6 +301,7 @@
 	sc->sc_dev = self;
 
 	mtx_init(&sc->sc_mtx, "usie", MTX_NETWORK_LOCK, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	TASK_INIT(&sc->sc_if_status_task, 0, usie_if_status_cb, sc);
 	TASK_INIT(&sc->sc_if_sync_task, 0, usie_if_sync_cb, sc);
@@ -482,12 +486,32 @@
 	for (x = 0; x != USIE_UCOM_MAX; x++)
 		usbd_transfer_unsetup(sc->sc_uc_xfer[x], USIE_UC_N_XFER);
 
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(self);
+
+	usie_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(usie);
+
 static void
+usie_free_softc(struct usie_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+usie_free(struct ucom_softc *ucom)
+{
+	usie_free_softc(ucom->sc_parent);
+}
+
+static void
 usie_uc_update_line_state(struct ucom_softc *ucom, uint8_t ls)
 {
 	struct usie_softc *sc = ucom->sc_parent;
@@ -772,7 +796,7 @@
 tr_setup:
 
 		if (sc->sc_rxm == NULL) {
-			sc->sc_rxm = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
+			sc->sc_rxm = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
 			    MJUMPAGESIZE /* could be bigger than MCLBYTES */ );
 		}
 		if (sc->sc_rxm == NULL) {
@@ -868,7 +892,7 @@
 			break;
 		}
 		/* copy aggregated frames to another mbuf */
-		m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 		if (__predict_false(m0 == NULL)) {
 			DPRINTF("could not allocate mbuf\n");
 			err++;
@@ -1364,7 +1388,7 @@
 	uint8_t *tmp;
 	uint8_t cns_len;
 
-	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	if (__predict_false(m == NULL)) {
 		DPRINTF("could not allocate mbuf\n");
 		ifp->if_ierrors++;

Modified: trunk/sys/dev/usb/net/uhso.c
===================================================================
--- trunk/sys/dev/usb/net/uhso.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/uhso.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -283,7 +283,7 @@
 #undef UHSO_DEV
 };
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW, 0, "USB uhso");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW, 0, "USB uhso");
 static int uhso_autoswitch = 1;
 SYSCTL_INT(_hw_usb_uhso, OID_AUTO, auto_switch, CTLFLAG_RW,
     &uhso_autoswitch, 0, "Automatically switch to modem mode");
@@ -455,6 +455,7 @@
 static int uhso_radio_sysctl(SYSCTL_HANDLER_ARGS);
 static int uhso_radio_ctrl(struct uhso_softc *, int);
 
+static void uhso_free(struct ucom_softc *);
 static void uhso_ucom_start_read(struct ucom_softc *);
 static void uhso_ucom_stop_read(struct ucom_softc *);
 static void uhso_ucom_start_write(struct ucom_softc *);
@@ -473,6 +474,7 @@
 static device_probe_t uhso_probe;
 static device_attach_t uhso_attach;
 static device_detach_t uhso_detach;
+static void uhso_free_softc(struct uhso_softc *);
 
 static device_method_t uhso_methods[] = {
 	DEVMETHOD(device_probe,		uhso_probe),
@@ -500,7 +502,8 @@
 	.ucom_start_read = uhso_ucom_start_read,
 	.ucom_stop_read = uhso_ucom_stop_read,
 	.ucom_start_write = uhso_ucom_start_write,
-	.ucom_stop_write = uhso_ucom_stop_write
+	.ucom_stop_write = uhso_ucom_stop_write,
+	.ucom_free = &uhso_free,
 };
 
 static int
@@ -537,7 +540,6 @@
 {
 	struct uhso_softc *sc = device_get_softc(self);
 	struct usb_attach_arg *uaa = device_get_ivars(self);
-	struct usb_config_descriptor *cd;
 	struct usb_interface_descriptor *id;
 	struct sysctl_ctx_list *sctx;
 	struct sysctl_oid *soid;
@@ -552,12 +554,12 @@
 	sc->sc_dev = self;
 	sc->sc_udev = uaa->device;
 	mtx_init(&sc->sc_mtx, "uhso", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_ucom = NULL;
 	sc->sc_ttys = 0;
 	sc->sc_radio = 1;
 
-	cd = usbd_get_config_descriptor(uaa->device);
 	id = usbd_get_interface_descriptor(uaa->iface);
 	sc->sc_ctrl_iface_no = id->bInterfaceNumber;
 
@@ -692,11 +694,31 @@
 		usbd_transfer_unsetup(sc->sc_if_xfer, UHSO_IFNET_MAX);
 	}
 
-	mtx_destroy(&sc->sc_mtx);
+	device_claim_softc(self);
+
+	uhso_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uhso);
+
 static void
+uhso_free_softc(struct uhso_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uhso_free(struct ucom_softc *ucom)
+{
+	uhso_free_softc(ucom->sc_parent);
+}
+
+static void
 uhso_test_autoinst(void *arg, struct usb_device *udev,
     struct usb_attach_arg *uaa)
 {
@@ -1597,7 +1619,7 @@
 	case USB_ST_TRANSFERRED:
 		if (actlen > 0 && (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) {
 			pc = usbd_xfer_get_frame(xfer, 0);
-			m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+			m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 			usbd_copy_out(pc, 0, mtod(m, uint8_t *), actlen);
 			m->m_pkthdr.len = m->m_len = actlen;
 			/* Enqueue frame for further processing */
@@ -1730,13 +1752,13 @@
 			 * Allocate a new mbuf for this IP packet and
 			 * copy the IP-packet into it.
 			 */
-			m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+			m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 			memcpy(mtod(m, uint8_t *), mtod(m0, uint8_t *), iplen);
 			m->m_pkthdr.len = m->m_len = iplen;
 
 			/* Adjust the size of the original mbuf */
 			m_adj(m0, iplen);
-			m0 = m_defrag(m0, M_WAIT);
+			m0 = m_defrag(m0, M_WAITOK);
 
 			UHSO_DPRINTF(3, "New mbuf=%p, len=%d/%d, m0=%p, "
 			    "m0_len=%d/%d\n", m, m->m_pkthdr.len, m->m_len,

Modified: trunk/sys/dev/usb/net/usb_ethernet.c
===================================================================
--- trunk/sys/dev/usb/net/usb_ethernet.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/net/usb_ethernet.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -57,7 +57,8 @@
 #include <dev/usb/usb_process.h>
 #include <dev/usb/net/usb_ethernet.h>
 
-SYSCTL_NODE(_net, OID_AUTO, ue, CTLFLAG_RD, 0, "USB Ethernet parameters");
+static SYSCTL_NODE(_net, OID_AUTO, ue, CTLFLAG_RD, 0,
+    "USB Ethernet parameters");
 
 #define	UE_LOCK(_ue)		mtx_lock((_ue)->ue_mtx)
 #define	UE_UNLOCK(_ue)		mtx_unlock((_ue)->ue_mtx)
@@ -557,7 +558,7 @@
 {
 	struct mbuf *m_new;
 
-	m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	m_new = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	if (m_new == NULL)
 		return (NULL);
 	m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;

Modified: trunk/sys/dev/usb/quirk/usb_quirk.c
===================================================================
--- trunk/sys/dev/usb/quirk/usb_quirk.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/quirk/usb_quirk.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -94,6 +94,7 @@
 	USB_QUIRK(SILICONPORTALS, YAPPHONE, 0x100, 0x100, UQ_AU_INP_ASYNC),
 	USB_QUIRK(LOGITECH, UN53B, 0x0000, 0xffff, UQ_NO_STRINGS),
 	USB_QUIRK(ELSA, MODEM1, 0x0000, 0xffff, UQ_CFG_INDEX_1),
+	USB_QUIRK(PLANEX2, MZKUE150N, 0x0000, 0xffff, UQ_CFG_INDEX_1),
 	/* Quirks for printer devices */
 	USB_QUIRK(HP, 895C, 0x0000, 0xffff, UQ_BROKEN_BIDIR),
 	USB_QUIRK(HP, 880C, 0x0000, 0xffff, UQ_BROKEN_BIDIR),
@@ -123,7 +124,10 @@
 	USB_QUIRK(METAGEEK2, WISPYDBX, 0x0000, 0xffff, UQ_KBD_IGNORE, UQ_HID_IGNORE),
 	USB_QUIRK(TENX, UAUDIO0, 0x0101, 0x0101, UQ_AUDIO_SWAP_LR),
 	/* MS keyboards do weird things */
+	USB_QUIRK(MICROSOFT, NATURAL4000, 0x0000, 0xFFFF, UQ_KBD_BOOTPROTO),
 	USB_QUIRK(MICROSOFT, WLINTELLIMOUSE, 0x0000, 0xffff, UQ_MS_LEADING_BYTE),
+	/* Quirk for Corsair Vengeance K60 keyboard */
+	USB_QUIRK(CORSAIR, K60, 0x0000, 0xffff, UQ_KBD_BOOTPROTO),
 	/* umodem(4) device quirks */
 	USB_QUIRK(METRICOM, RICOCHET_GS, 0x100, 0x100, UQ_ASSUME_CM_OVER_DATA),
 	USB_QUIRK(SANYO, SCP4900, 0x000, 0x000, UQ_ASSUME_CM_OVER_DATA),
@@ -174,6 +178,7 @@
 	    UQ_MSC_FORCE_PROTO_SCSI),
 	USB_QUIRK(DMI, CFSM_RW, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI,
 	    UQ_MSC_NO_GETMAXLUN),
+	USB_QUIRK(EMTEC, RUF2PS, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
 	USB_QUIRK(EPSON, STYLUS_875DC, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI,
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
 	USB_QUIRK(EPSON, STYLUS_895, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -180,6 +185,7 @@
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
 	USB_QUIRK(FEIYA, 5IN1, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
 	    UQ_MSC_FORCE_PROTO_SCSI),
+	USB_QUIRK(FEIYA, ELANGO, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
 	USB_QUIRK(FREECOM, DVD, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
 	USB_QUIRK(FUJIPHOTO, MASS0100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I,
 	    UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA, UQ_MSC_NO_SYNC_CACHE),
@@ -297,7 +303,7 @@
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
 	USB_QUIRK(ONSPEC, READER, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
 	USB_QUIRK(ONSPEC, UCF100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
-	    UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_INQUIRY | UQ_MSC_NO_GETMAXLUN),
+	    UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_GETMAXLUN),
 	USB_QUIRK(ONSPEC2, IMAGEMATE_SDDR55, 0x0000, 0xffff,
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
 	USB_QUIRK(PANASONIC, KXL840AN, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -333,6 +339,8 @@
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_IGNORE_RESIDUE),
 	USB_QUIRK(SANDISK, SDDR31, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_READ_CAP_OFFBY1),
+	USB_QUIRK(SANDISK, IMAGEMATE_SDDR289, 0x0000, 0xffff,
+	    UQ_MSC_NO_SYNC_CACHE, UQ_MSC_NO_GETMAXLUN),
 	USB_QUIRK(SCANLOGIC, SL11R, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
 	    UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_INQUIRY),
 	USB_QUIRK(SHUTTLE, EUSB, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I,
@@ -385,6 +393,7 @@
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
 	USB_QUIRK(SONY, PORTABLE_HDD_V2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
 	    UQ_MSC_FORCE_PROTO_SCSI),
+	USB_QUIRK(STMICRO, ST72682, 0x0000, 0xffff, UQ_MSC_NO_PREVENT_ALLOW),
 	USB_QUIRK(SUPERTOP, IDE, 0x0000, 0xffff, UQ_MSC_IGNORE_RESIDUE,
 	    UQ_MSC_NO_SYNC_CACHE),
 	USB_QUIRK(TAUGA, CAMERAMATE, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
@@ -437,6 +446,9 @@
 	USB_QUIRK(MEIZU, M6_SL, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_SYNC_CACHE),
 
+	USB_QUIRK(TOSHIBA, TRANSMEMORY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+	USB_QUIRK(VIALABS, USB30SATABRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+
 	/* Non-standard USB MIDI devices */
 	USB_QUIRK(ROLAND, UM1, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
 	USB_QUIRK(ROLAND, SC8850, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
@@ -454,13 +466,24 @@
 	USB_QUIRK(ROLAND, SD20, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
 	USB_QUIRK(ROLAND, SD80, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
 	USB_QUIRK(ROLAND, UA700, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+	USB_QUIRK(EGO, M4U, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI),
+	USB_QUIRK(LOGILINK, U2M, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI),
 	USB_QUIRK(MEDELI, DD305, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI, UQ_MATCH_VENDOR_ONLY),
+	USB_QUIRK(REDOCTANE, GHMIDI, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI),
+	USB_QUIRK(TEXTECH, U2M_1, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI),
+	USB_QUIRK(TEXTECH, U2M_2, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI),
+	USB_QUIRK(WCH2, U2M, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI),
 
+	/* Non-standard USB AUDIO devices */
+	USB_QUIRK(MAUDIO, FASTTRACKULTRA, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+	USB_QUIRK(MAUDIO, FASTTRACKULTRA8R, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+
 	/*
 	 * Quirks for manufacturers which USB devices does not respond
 	 * after issuing non-supported commands:
 	 */
 	USB_QUIRK(ALCOR, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MSC_NO_TEST_UNIT_READY, UQ_MATCH_VENDOR_ONLY),
+	USB_QUIRK(APPLE, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
 	USB_QUIRK(FEIYA, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
 	USB_QUIRK(REALTEK, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
 	USB_QUIRK(INITIO, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
@@ -482,6 +505,7 @@
 	[UQ_HID_IGNORE]		= "UQ_HID_IGNORE",
 	[UQ_KBD_IGNORE]		= "UQ_KBD_IGNORE",
 	[UQ_KBD_BOOTPROTO]	= "UQ_KBD_BOOTPROTO",
+	[UQ_UMS_IGNORE]		= "UQ_UMS_IGNORE",
 	[UQ_MS_BAD_CLASS]	= "UQ_MS_BAD_CLASS",
 	[UQ_MS_LEADING_BYTE]	= "UQ_MS_LEADING_BYTE",
 	[UQ_MS_REVZ]		= "UQ_MS_REVZ",
@@ -502,6 +526,7 @@
 	[UQ_MSC_NO_GETMAXLUN]		= "UQ_MSC_NO_GETMAXLUN",
 	[UQ_MSC_NO_INQUIRY]		= "UQ_MSC_NO_INQUIRY",
 	[UQ_MSC_NO_INQUIRY_EVPD]	= "UQ_MSC_NO_INQUIRY_EVPD",
+	[UQ_MSC_NO_PREVENT_ALLOW]	= "UQ_MSC_NO_PREVENT_ALLOW",
 	[UQ_MSC_NO_SYNC_CACHE]		= "UQ_MSC_NO_SYNC_CACHE",
 	[UQ_MSC_SHUTTLE_INIT]		= "UQ_MSC_SHUTTLE_INIT",
 	[UQ_MSC_ALT_IFACE_1]		= "UQ_MSC_ALT_IFACE_1",
@@ -776,7 +801,7 @@
 		}
 		if (x == USB_SUB_QUIRKS_MAX) {
 			/* all quirk entries are unused - release */
-			memset(pqe, 0, sizeof(pqe));
+			memset(pqe, 0, sizeof(*pqe));
 		}
 		mtx_unlock(&usb_quirk_mtx);
 		return (0);		/* success */

Modified: trunk/sys/dev/usb/quirk/usb_quirk.h
===================================================================
--- trunk/sys/dev/usb/quirk/usb_quirk.h	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/quirk/usb_quirk.h	2013-12-28 15:28:46 UTC (rev 6568)
@@ -29,7 +29,7 @@
 
 enum {
 	/*
-	 * Keep in sync with theusb_quirk_str usb_quirk.c, and with the
+	 * Keep in sync with usb_quirk_str in usb_quirk.c, and with
 	 * share/man/man4/usb_quirk.4
 	 */
 	UQ_NONE,		/* not a valid quirk */
@@ -49,6 +49,7 @@
 	UQ_HID_IGNORE,		/* device should be ignored by hid class */
 	UQ_KBD_IGNORE,		/* device should be ignored by kbd class */
 	UQ_KBD_BOOTPROTO,	/* device should set the boot protocol */
+	UQ_UMS_IGNORE,          /* device should be ignored by ums class */
 	UQ_MS_BAD_CLASS,	/* doesn't identify properly */
 	UQ_MS_LEADING_BYTE,	/* mouse sends an unknown leading byte */
 	UQ_MS_REVZ,		/* mouse has Z-axis reversed */
@@ -64,7 +65,10 @@
 	UQ_CFG_INDEX_0,		/* select configuration index 0 by default */
 	UQ_ASSUME_CM_OVER_DATA,	/* assume cm over data feature */
 
-	/* USB Mass Storage Quirks. See "storage/umass.c" for a detailed description. */
+	/*
+	 * USB Mass Storage Quirks. See "storage/umass.c" for a
+	 * detailed description.
+	 */
 	UQ_MSC_NO_TEST_UNIT_READY,	/* send start/stop instead of TUR */
 	UQ_MSC_NO_RS_CLEAR_UA,		/* does not reset Unit Att. */
 	UQ_MSC_NO_START_STOP,		/* does not support start/stop */
@@ -71,6 +75,7 @@
 	UQ_MSC_NO_GETMAXLUN,		/* does not support get max LUN */
 	UQ_MSC_NO_INQUIRY,		/* fake generic inq response */
 	UQ_MSC_NO_INQUIRY_EVPD,		/* does not support inq EVPD */
+	UQ_MSC_NO_PREVENT_ALLOW,	/* does not support medium removal */ 
 	UQ_MSC_NO_SYNC_CACHE,		/* does not support sync cache */ 
 	UQ_MSC_SHUTTLE_INIT,		/* requires Shuttle init sequence */
 	UQ_MSC_ALT_IFACE_1,		/* switch to alternate interface 1 */

Modified: trunk/sys/dev/usb/serial/u3g.c
===================================================================
--- trunk/sys/dev/usb/serial/u3g.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/u3g.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -53,6 +53,7 @@
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
+#include <dev/usb/usb_cdc.h>
 #include "usbdevs.h"
 
 #define	USB_DEBUG_VAR u3g_debug
@@ -66,7 +67,7 @@
 #ifdef USB_DEBUG
 static int u3g_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, u3g, CTLFLAG_RW, 0, "USB 3g");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, u3g, CTLFLAG_RW, 0, "USB 3g");
 SYSCTL_INT(_hw_usb_u3g, OID_AUTO, debug, CTLFLAG_RW,
     &u3g_debug, 0, "Debug level");
 #endif
@@ -99,6 +100,7 @@
 enum {
 	U3G_BULK_WR,
 	U3G_BULK_RD,
+	U3G_INTR,
 	U3G_N_TRANSFER,
 };
 
@@ -107,25 +109,35 @@
 	struct ucom_softc sc_ucom[U3G_MAXPORTS];
 
 	struct usb_xfer *sc_xfer[U3G_MAXPORTS][U3G_N_TRANSFER];
+	uint8_t sc_iface[U3G_MAXPORTS];			/* local status register */
+	uint8_t sc_lsr[U3G_MAXPORTS];			/* local status register */
+	uint8_t sc_msr[U3G_MAXPORTS];			/* u3g status register */
+	uint16_t sc_line[U3G_MAXPORTS];			/* line status */
+
 	struct usb_device *sc_udev;
 	struct mtx sc_mtx;
 
-	uint8_t	sc_lsr;			/* local status register */
-	uint8_t	sc_msr;			/* U3G status register */
-	uint8_t	sc_numports;
+	uint8_t sc_numports;
 };
 
 static device_probe_t u3g_probe;
 static device_attach_t u3g_attach;
 static device_detach_t u3g_detach;
+static void u3g_free_softc(struct u3g_softc *);
 
 static usb_callback_t u3g_write_callback;
 static usb_callback_t u3g_read_callback;
+static usb_callback_t u3g_intr_callback;
 
+static void u3g_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
+static void u3g_cfg_set_dtr(struct ucom_softc *, uint8_t);
+static void u3g_cfg_set_rts(struct ucom_softc *, uint8_t);
 static void u3g_start_read(struct ucom_softc *ucom);
 static void u3g_stop_read(struct ucom_softc *ucom);
 static void u3g_start_write(struct ucom_softc *ucom);
 static void u3g_stop_write(struct ucom_softc *ucom);
+static void u3g_poll(struct ucom_softc *ucom);
+static void u3g_free(struct ucom_softc *ucom);
 
 
 static void u3g_test_autoinst(void *, struct usb_device *,
@@ -153,13 +165,27 @@
 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
 		.callback = &u3g_read_callback,
 	},
+
+	[U3G_INTR] = {
+		.type = UE_INTERRUPT,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,},
+		.bufsize = 0,	/* use wMaxPacketSize */
+		.callback = &u3g_intr_callback,
+	},
 };
 
 static const struct ucom_callback u3g_callback = {
+	.ucom_cfg_get_status = &u3g_cfg_get_status,
+	.ucom_cfg_set_dtr = &u3g_cfg_set_dtr,
+	.ucom_cfg_set_rts = &u3g_cfg_set_rts,
 	.ucom_start_read = &u3g_start_read,
 	.ucom_stop_read = &u3g_stop_read,
 	.ucom_start_write = &u3g_start_write,
 	.ucom_stop_write = &u3g_stop_write,
+	.ucom_poll = &u3g_poll,
+	.ucom_free = &u3g_free,
 };
 
 static device_method_t u3g_methods[] = {
@@ -166,7 +192,7 @@
 	DEVMETHOD(device_probe, u3g_probe),
 	DEVMETHOD(device_attach, u3g_attach),
 	DEVMETHOD(device_detach, u3g_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t u3g_devclass;
@@ -187,6 +213,7 @@
 	U3G_DEV(ACERP, H10, 0),
 	U3G_DEV(AIRPLUS, MCD650, 0),
 	U3G_DEV(AIRPRIME, PC5220, 0),
+	U3G_DEV(AIRPRIME, AC313U, 0),
 	U3G_DEV(ALINK, 3G, 0),
 	U3G_DEV(ALINK, 3GU, 0),
 	U3G_DEV(ALINK, DWM652U5, 0),
@@ -215,6 +242,8 @@
 	U3G_DEV(DELL, U5730_2, 0),
 	U3G_DEV(DELL, U5730_3, 0),
 	U3G_DEV(DELL, U740, 0),
+	U3G_DEV(DLINK, DWR510_CD, U3GINIT_SCSIEJECT),
+	U3G_DEV(DLINK, DWR510, 0),
 	U3G_DEV(DLINK3, DWM652, 0),
 	U3G_DEV(HP, EV2200, 0),
 	U3G_DEV(HP, HS2300, 0),
@@ -282,14 +311,22 @@
 	U3G_DEV(HUAWEI, E143F, U3GINIT_HUAWEI),
 	U3G_DEV(HUAWEI, E173, 0),
 	U3G_DEV(HUAWEI, E173_INIT, U3GINIT_HUAWEISCSI),
+	U3G_DEV(HUAWEI, E3131, 0),
+	U3G_DEV(HUAWEI, E3131_INIT, U3GINIT_HUAWEISCSI),
 	U3G_DEV(HUAWEI, E180V, U3GINIT_HUAWEI),
 	U3G_DEV(HUAWEI, E220, U3GINIT_HUAWEI),
 	U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI),
+	U3G_DEV(HUAWEI, E392, U3GINIT_HUAWEISCSI),
 	U3G_DEV(HUAWEI, MOBILE, U3GINIT_HUAWEI),
 	U3G_DEV(HUAWEI, E1752, U3GINIT_HUAWEISCSI),
 	U3G_DEV(HUAWEI, E1820, U3GINIT_HUAWEISCSI),
 	U3G_DEV(HUAWEI, K3765, U3GINIT_HUAWEI),
 	U3G_DEV(HUAWEI, K3765_INIT, U3GINIT_HUAWEISCSI),
+	U3G_DEV(HUAWEI, K3770, U3GINIT_HUAWEI),
+	U3G_DEV(HUAWEI, K3770_INIT, U3GINIT_HUAWEISCSI),
+	U3G_DEV(HUAWEI, K4505, U3GINIT_HUAWEI),
+	U3G_DEV(HUAWEI, K4505_INIT, U3GINIT_HUAWEISCSI),
+	U3G_DEV(HUAWEI, ETS2055, U3GINIT_HUAWEI),
 	U3G_DEV(KYOCERA2, CDMA_MSM_K, 0),
 	U3G_DEV(KYOCERA2, KPC680, 0),
 	U3G_DEV(LONGCHEER, WM66, U3GINIT_HUAWEI),
@@ -307,6 +344,7 @@
 	U3G_DEV(NOVATEL, MC760, 0),
 	U3G_DEV(NOVATEL, MC547, 0),
 	U3G_DEV(NOVATEL, MC950D, 0),
+	U3G_DEV(NOVATEL, MIFI2200, U3GINIT_SCSIEJECT),
 	U3G_DEV(NOVATEL, U720, 0),
 	U3G_DEV(NOVATEL, U727, 0),
 	U3G_DEV(NOVATEL, U727_2, 0),
@@ -320,6 +358,7 @@
 	U3G_DEV(NOVATEL, V740, 0),
 	U3G_DEV(NOVATEL, X950D, 0),
 	U3G_DEV(NOVATEL, XU870, 0),
+	U3G_DEV(MOTOROLA2, MB886, U3GINIT_SCSIEJECT),
 	U3G_DEV(OPTION, E6500, 0),
 	U3G_DEV(OPTION, E6501, 0),
 	U3G_DEV(OPTION, E6601, 0),
@@ -352,10 +391,13 @@
 	U3G_DEV(QISDA, H20_2, 0),
 	U3G_DEV(QISDA, H21_1, 0),
 	U3G_DEV(QISDA, H21_2, 0),
+	U3G_DEV(QUALCOMM, NTT_L02C_MODEM, U3GINIT_SCSIEJECT),
 	U3G_DEV(QUALCOMM2, AC8700, 0),
 	U3G_DEV(QUALCOMM2, MF330, 0),
 	U3G_DEV(QUALCOMM2, SIM5218, 0),
 	U3G_DEV(QUALCOMM2, VW110L, U3GINIT_SCSIEJECT),
+	U3G_DEV(QUALCOMM2, GOBI2000_QDL, 0),
+	U3G_DEV(QUALCOMM2, GOBI2000, 0),
 	U3G_DEV(QUALCOMMINC, AC2726, 0),
 	U3G_DEV(QUALCOMMINC, AC8700, 0),
 	U3G_DEV(QUALCOMMINC, AC8710, 0),
@@ -799,6 +841,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "u3g", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_udev = uaa->device;
 
@@ -839,6 +882,15 @@
 			continue;
 		}
 
+		iface = usbd_get_iface(uaa->device, i);
+		id = usbd_get_interface_descriptor(iface);
+		sc->sc_iface[nports] = id->bInterfaceNumber;
+
+		if (bootverbose && sc->sc_xfer[nports][U3G_INTR]) {
+			device_printf(dev, "port %d supports modem control",
+				      nports);
+		}
+
 		/* set stall by default */
 		mtx_lock(&sc->sc_mtx);
 		usbd_xfer_set_stall(sc->sc_xfer[nports][U3G_BULK_WR]);
@@ -886,19 +938,41 @@
 
 	for (subunit = 0; subunit != U3G_MAXPORTS; subunit++)
 		usbd_transfer_unsetup(sc->sc_xfer[subunit], U3G_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	u3g_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(u3g);
+
 static void
+u3g_free_softc(struct u3g_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+u3g_free(struct ucom_softc *ucom)
+{
+	u3g_free_softc(ucom->sc_parent);
+}
+
+static void
 u3g_start_read(struct ucom_softc *ucom)
 {
 	struct u3g_softc *sc = ucom->sc_parent;
 
+	/* start interrupt endpoint (if configured) */
+	usbd_transfer_start(sc->sc_xfer[ucom->sc_subunit][U3G_INTR]);
+
 	/* start read endpoint */
 	usbd_transfer_start(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_RD]);
-	return;
 }
 
 static void
@@ -906,9 +980,11 @@
 {
 	struct u3g_softc *sc = ucom->sc_parent;
 
+	/* stop interrupt endpoint (if configured) */
+	usbd_transfer_stop(sc->sc_xfer[ucom->sc_subunit][U3G_INTR]);
+
 	/* stop read endpoint */
 	usbd_transfer_stop(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_RD]);
-	return;
 }
 
 static void
@@ -917,7 +993,6 @@
 	struct u3g_softc *sc = ucom->sc_parent;
 
 	usbd_transfer_start(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_WR]);
-	return;
 }
 
 static void
@@ -926,7 +1001,6 @@
 	struct u3g_softc *sc = ucom->sc_parent;
 
 	usbd_transfer_stop(sc->sc_xfer[ucom->sc_subunit][U3G_BULK_WR]);
-	return;
 }
 
 static void
@@ -955,7 +1029,6 @@
 		}
 		break;
 	}
-	return;
 }
 
 static void
@@ -986,5 +1059,135 @@
 		}
 		break;
 	}
-	return;
 }
+
+static void
+u3g_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
+{
+	struct u3g_softc *sc = ucom->sc_parent;
+
+	*lsr = sc->sc_lsr[ucom->sc_subunit];
+	*msr = sc->sc_msr[ucom->sc_subunit];
+}
+
+static void
+u3g_cfg_set_line(struct ucom_softc *ucom)
+{
+	struct u3g_softc *sc = ucom->sc_parent;
+	struct usb_device_request req;
+
+	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+	req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
+	USETW(req.wValue, sc->sc_line[ucom->sc_subunit]);
+	req.wIndex[0] = sc->sc_iface[ucom->sc_subunit];
+	req.wIndex[1] = 0;
+	USETW(req.wLength, 0);
+
+	ucom_cfg_do_request(sc->sc_udev, ucom,
+	    &req, NULL, 0, 1000);
+}
+
+static void
+u3g_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
+{
+	struct u3g_softc *sc = ucom->sc_parent;
+
+	DPRINTF("onoff = %d\n", onoff);
+
+	if (onoff)
+		sc->sc_line[ucom->sc_subunit] |= UCDC_LINE_DTR;
+	else
+		sc->sc_line[ucom->sc_subunit] &= ~UCDC_LINE_DTR;
+
+	u3g_cfg_set_line(ucom);
+}
+
+static void
+u3g_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
+{
+	struct u3g_softc *sc = ucom->sc_parent;
+
+	DPRINTF("onoff = %d\n", onoff);
+
+	if (onoff)
+		sc->sc_line[ucom->sc_subunit] |= UCDC_LINE_RTS;
+	else
+		sc->sc_line[ucom->sc_subunit] &= ~UCDC_LINE_RTS;
+
+	u3g_cfg_set_line(ucom);
+}
+
+static void
+u3g_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct ucom_softc *ucom = usbd_xfer_softc(xfer);
+	struct u3g_softc *sc = ucom->sc_parent;
+	struct usb_page_cache *pc;
+	struct usb_cdc_notification pkt;
+	int actlen;
+	uint16_t wLen;
+	uint8_t mstatus;
+
+	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		if (actlen < 8) {	/* usb_cdc_notification with 2 data bytes */
+			DPRINTF("message too short (expected 8, received %d)\n", actlen);
+			goto tr_setup;
+		}
+		pc = usbd_xfer_get_frame(xfer, 0);
+		usbd_copy_out(pc, 0, &pkt, actlen);
+
+		wLen = UGETW(pkt.wLength);
+		if (wLen < 2) {
+			DPRINTF("message too short (expected 2 data bytes, received %d)\n", wLen);
+			goto tr_setup;
+		}
+
+		if (pkt.bmRequestType == UCDC_NOTIFICATION
+		    && pkt.bNotification == UCDC_N_SERIAL_STATE) {
+			/*
+		         * Set the serial state in ucom driver based on
+		         * the bits from the notify message
+		         */
+			DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
+			    pkt.data[0], pkt.data[1]);
+
+			/* currently, lsr is always zero. */
+			sc->sc_lsr[ucom->sc_subunit] = 0;
+			sc->sc_msr[ucom->sc_subunit] = 0;
+
+			mstatus = pkt.data[0];
+
+			if (mstatus & UCDC_N_SERIAL_RI)
+				sc->sc_msr[ucom->sc_subunit] |= SER_RI;
+			if (mstatus & UCDC_N_SERIAL_DSR)
+				sc->sc_msr[ucom->sc_subunit] |= SER_DSR;
+			if (mstatus & UCDC_N_SERIAL_DCD)
+				sc->sc_msr[ucom->sc_subunit] |= SER_DCD;
+			ucom_status_change(ucom);
+		}
+
+	case USB_ST_SETUP:
+tr_setup:
+		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+		usbd_transfer_submit(xfer);
+		return;
+
+	default:			/* Error */
+		if (error != USB_ERR_CANCELLED) {
+			/* try to clear stall first */
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
+		}
+		return;
+	}
+}
+
+static void
+u3g_poll(struct ucom_softc *ucom)
+{
+	struct u3g_softc *sc = ucom->sc_parent;
+	usbd_transfer_poll(sc->sc_xfer[ucom->sc_subunit], U3G_N_TRANSFER);
+}

Modified: trunk/sys/dev/usb/serial/uark.c
===================================================================
--- trunk/sys/dev/usb/serial/uark.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uark.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -99,10 +99,12 @@
 static device_probe_t uark_probe;
 static device_attach_t uark_attach;
 static device_detach_t uark_detach;
+static void uark_free_softc(struct uark_softc *);
 
 static usb_callback_t uark_bulk_write_callback;
 static usb_callback_t uark_bulk_read_callback;
 
+static void	uark_free(struct ucom_softc *);
 static void	uark_start_read(struct ucom_softc *);
 static void	uark_stop_read(struct ucom_softc *);
 static void	uark_start_write(struct ucom_softc *);
@@ -147,6 +149,7 @@
 	.ucom_start_write = &uark_start_write,
 	.ucom_stop_write = &uark_stop_write,
 	.ucom_poll = &uark_poll,
+	.ucom_free = &uark_free,
 };
 
 static device_method_t uark_methods[] = {
@@ -154,7 +157,7 @@
 	DEVMETHOD(device_probe, uark_probe),
 	DEVMETHOD(device_attach, uark_attach),
 	DEVMETHOD(device_detach, uark_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t uark_devclass;
@@ -201,6 +204,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uark", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_udev = uaa->device;
 
@@ -242,12 +246,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UARK_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uark_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uark);
+
 static void
+uark_free_softc(struct uark_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uark_free(struct ucom_softc *ucom)
+{
+	uark_free_softc(ucom->sc_parent);
+}
+
+static void
 uark_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct uark_softc *sc = usbd_xfer_softc(xfer);

Modified: trunk/sys/dev/usb/serial/ubsa.c
===================================================================
--- trunk/sys/dev/usb/serial/ubsa.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/ubsa.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -95,7 +95,7 @@
 #ifdef USB_DEBUG
 static int ubsa_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa");
 SYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RW,
     &ubsa_debug, 0, "ubsa debug level");
 #endif
@@ -176,6 +176,7 @@
 static device_probe_t ubsa_probe;
 static device_attach_t ubsa_attach;
 static device_detach_t ubsa_detach;
+static void ubsa_free_softc(struct ubsa_softc *);
 
 static usb_callback_t ubsa_write_callback;
 static usb_callback_t ubsa_read_callback;
@@ -182,6 +183,7 @@
 static usb_callback_t ubsa_intr_callback;
 
 static void	ubsa_cfg_request(struct ubsa_softc *, uint8_t, uint16_t);
+static void	ubsa_free(struct ucom_softc *);
 static void	ubsa_cfg_set_dtr(struct ucom_softc *, uint8_t);
 static void	ubsa_cfg_set_rts(struct ucom_softc *, uint8_t);
 static void	ubsa_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -237,6 +239,7 @@
 	.ucom_start_write = &ubsa_start_write,
 	.ucom_stop_write = &ubsa_stop_write,
 	.ucom_poll = &ubsa_poll,
+	.ucom_free = &ubsa_free,
 };
 
 static const STRUCT_USB_HOST_ID ubsa_devs[] = {
@@ -262,7 +265,7 @@
 	DEVMETHOD(device_probe, ubsa_probe),
 	DEVMETHOD(device_attach, ubsa_attach),
 	DEVMETHOD(device_detach, ubsa_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t ubsa_devclass;
@@ -306,6 +309,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "ubsa", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_udev = uaa->device;
 	sc->sc_iface_no = uaa->info.bIfaceNum;
@@ -348,12 +352,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UBSA_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	ubsa_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(ubsa);
+
 static void
+ubsa_free_softc(struct ubsa_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+ubsa_free(struct ucom_softc *ucom)
+{
+	ubsa_free_softc(ucom->sc_parent);
+}
+
+static void
 ubsa_cfg_request(struct ubsa_softc *sc, uint8_t index, uint16_t value)
 {
 	struct usb_device_request req;

Modified: trunk/sys/dev/usb/serial/ubser.c
===================================================================
--- trunk/sys/dev/usb/serial/ubser.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/ubser.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -2,8 +2,8 @@
  * Copyright (c) 2004 Bernd Walter <ticso at FreeBSD.org>
  *
  * $URL: https://devel.bwct.de/svn/projects/ubser/ubser.c $
- * $Date: 2013-01-08 02:57:52 $
- * $Author: laffer1 $
+ * $Date: 2004-02-29 01:53:10 +0100 (Sun, 29 Feb 2004) $
+ * $Author: ticso $
  * $Rev: 1127 $
  */
 
@@ -116,7 +116,7 @@
 #ifdef USB_DEBUG
 static int ubser_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser");
 SYSCTL_INT(_hw_usb_ubser, OID_AUTO, debug, CTLFLAG_RW,
     &ubser_debug, 0, "ubser debug level");
 #endif
@@ -141,7 +141,6 @@
 	uint8_t	sc_iface_no;
 	uint8_t	sc_iface_index;
 	uint8_t	sc_curr_tx_unit;
-	uint8_t	sc_name[16];
 };
 
 /* prototypes */
@@ -149,10 +148,12 @@
 static device_probe_t ubser_probe;
 static device_attach_t ubser_attach;
 static device_detach_t ubser_detach;
+static void ubser_free_softc(struct ubser_softc *);
 
 static usb_callback_t ubser_write_callback;
 static usb_callback_t ubser_read_callback;
 
+static void	ubser_free(struct ucom_softc *);
 static int	ubser_pre_param(struct ucom_softc *, struct termios *);
 static void	ubser_cfg_set_break(struct ucom_softc *, uint8_t);
 static void	ubser_cfg_get_status(struct ucom_softc *, uint8_t *,
@@ -193,6 +194,7 @@
 	.ucom_start_write = &ubser_start_write,
 	.ucom_stop_write = &ubser_stop_write,
 	.ucom_poll = &ubser_poll,
+	.ucom_free = &ubser_free,
 };
 
 static device_method_t ubser_methods[] = {
@@ -199,7 +201,7 @@
 	DEVMETHOD(device_probe, ubser_probe),
 	DEVMETHOD(device_attach, ubser_attach),
 	DEVMETHOD(device_detach, ubser_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t ubser_devclass;
@@ -243,10 +245,8 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "ubser", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
-	snprintf(sc->sc_name, sizeof(sc->sc_name), "%s",
-	    device_get_nameunit(dev));
-
 	sc->sc_iface_no = uaa->info.bIfaceNum;
 	sc->sc_iface_index = uaa->info.bIfaceIndex;
 	sc->sc_udev = uaa->device;
@@ -319,11 +319,31 @@
 
 	ucom_detach(&sc->sc_super_ucom, sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UBSER_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	ubser_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(ubser);
+
+static void
+ubser_free_softc(struct ubser_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+ubser_free(struct ucom_softc *ucom)
+{
+	ubser_free_softc(ucom->sc_parent);
+}
+
 static int
 ubser_pre_param(struct ucom_softc *ucom, struct termios *t)
 {

Modified: trunk/sys/dev/usb/serial/uchcom.c
===================================================================
--- trunk/sys/dev/usb/serial/uchcom.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uchcom.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -103,7 +103,7 @@
 #ifdef USB_DEBUG
 static int uchcom_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uchcom, CTLFLAG_RW, 0, "USB uchcom");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uchcom, CTLFLAG_RW, 0, "USB uchcom");
 SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RW,
     &uchcom_debug, 0, "uchcom debug level");
 #endif
@@ -207,10 +207,12 @@
 static const STRUCT_USB_HOST_ID uchcom_devs[] = {
 	{USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)},
 	{USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)},
+	{USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER_2, 0)},
 };
 
 /* protypes */
 
+static void	uchcom_free(struct ucom_softc *);
 static int	uchcom_pre_param(struct ucom_softc *, struct termios *);
 static void	uchcom_cfg_get_status(struct ucom_softc *, uint8_t *,
 		    uint8_t *);
@@ -234,6 +236,7 @@
 static device_probe_t uchcom_probe;
 static device_attach_t uchcom_attach;
 static device_detach_t uchcom_detach;
+static void uchcom_free_softc(struct uchcom_softc *);
 
 static usb_callback_t uchcom_intr_callback;
 static usb_callback_t uchcom_write_callback;
@@ -282,6 +285,7 @@
 	.ucom_start_write = &uchcom_start_write,
 	.ucom_stop_write = &uchcom_stop_write,
 	.ucom_poll = &uchcom_poll,
+	.ucom_free = &uchcom_free,
 };
 
 /* ----------------------------------------------------------------------
@@ -319,6 +323,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uchcom", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_udev = uaa->device;
 
@@ -371,11 +376,31 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UCHCOM_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uchcom_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uchcom);
+
+static void
+uchcom_free_softc(struct uchcom_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uchcom_free(struct ucom_softc *ucom)
+{
+	uchcom_free_softc(ucom->sc_parent);
+}
+
 /* ----------------------------------------------------------------------
  * low level i/o
  */
@@ -841,12 +866,11 @@
 	DEVMETHOD(device_probe, uchcom_probe),
 	DEVMETHOD(device_attach, uchcom_attach),
 	DEVMETHOD(device_detach, uchcom_detach),
-
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static driver_t uchcom_driver = {
-	.name = "ucom",
+	.name = "uchcom",
 	.methods = uchcom_methods,
 	.size = sizeof(struct uchcom_softc)
 };

Modified: trunk/sys/dev/usb/serial/ucycom.c
===================================================================
--- trunk/sys/dev/usb/serial/ucycom.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/ucycom.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -101,7 +101,6 @@
 #define	UCYCOM_CFG_STOPB	0x08
 #define	UCYCOM_CFG_DATAB	0x03
 	uint8_t	sc_ist;			/* status flags from last input */
-	uint8_t	sc_name[16];
 	uint8_t	sc_iface_no;
 	uint8_t	sc_temp_cfg[32];
 };
@@ -111,10 +110,12 @@
 static device_probe_t ucycom_probe;
 static device_attach_t ucycom_attach;
 static device_detach_t ucycom_detach;
+static void ucycom_free_softc(struct ucycom_softc *);
 
 static usb_callback_t ucycom_ctrl_write_callback;
 static usb_callback_t ucycom_intr_read_callback;
 
+static void	ucycom_free(struct ucom_softc *);
 static void	ucycom_cfg_open(struct ucom_softc *);
 static void	ucycom_start_read(struct ucom_softc *);
 static void	ucycom_stop_read(struct ucom_softc *);
@@ -155,6 +156,7 @@
 	.ucom_start_write = &ucycom_start_write,
 	.ucom_stop_write = &ucycom_stop_write,
 	.ucom_poll = &ucycom_poll,
+	.ucom_free = &ucycom_free,
 };
 
 static device_method_t ucycom_methods[] = {
@@ -161,7 +163,7 @@
 	DEVMETHOD(device_probe, ucycom_probe),
 	DEVMETHOD(device_attach, ucycom_attach),
 	DEVMETHOD(device_detach, ucycom_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t ucycom_devclass;
@@ -218,10 +220,8 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "ucycom", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
-	snprintf(sc->sc_name, sizeof(sc->sc_name),
-	    "%s", device_get_nameunit(dev));
-
 	DPRINTF("\n");
 
 	/* get chip model */
@@ -297,12 +297,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UCYCOM_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	ucycom_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(ucycom);
+
 static void
+ucycom_free_softc(struct ucycom_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+ucycom_free(struct ucom_softc *ucom)
+{
+	ucycom_free_softc(ucom->sc_parent);
+}
+
+static void
 ucycom_cfg_open(struct ucom_softc *ucom)
 {
 	struct ucycom_softc *sc = ucom->sc_parent;

Modified: trunk/sys/dev/usb/serial/ufoma.c
===================================================================
--- trunk/sys/dev/usb/serial/ufoma.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/ufoma.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -195,7 +195,6 @@
 	uint8_t	sc_msr;
 	uint8_t	sc_modetoactivate;
 	uint8_t	sc_currentmode;
-	uint8_t	sc_name[16];
 };
 
 /* prototypes */
@@ -203,6 +202,7 @@
 static device_probe_t ufoma_probe;
 static device_attach_t ufoma_attach;
 static device_detach_t ufoma_detach;
+static void ufoma_free_softc(struct ufoma_softc *);
 
 static usb_callback_t ufoma_ctrl_read_callback;
 static usb_callback_t ufoma_ctrl_write_callback;
@@ -214,6 +214,7 @@
 		    struct usb_interface_descriptor *, uint8_t, uint8_t);
 static void	ufoma_cfg_link_state(struct ufoma_softc *);
 static void	ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t);
+static void	ufoma_free(struct ucom_softc *);
 static void	ufoma_cfg_open(struct ucom_softc *);
 static void	ufoma_cfg_close(struct ucom_softc *);
 static void	ufoma_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -304,6 +305,7 @@
 	.ucom_start_write = &ufoma_start_write,
 	.ucom_stop_write = &ufoma_stop_write,
 	.ucom_poll = &ufoma_poll,
+	.ucom_free = &ufoma_free,
 };
 
 static device_method_t ufoma_methods[] = {
@@ -311,7 +313,7 @@
 	DEVMETHOD(device_probe, ufoma_probe),
 	DEVMETHOD(device_attach, ufoma_attach),
 	DEVMETHOD(device_detach, ufoma_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t ufoma_devclass;
@@ -385,13 +387,11 @@
 	sc->sc_unit = device_get_unit(dev);
 
 	mtx_init(&sc->sc_mtx, "ufoma", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 	cv_init(&sc->sc_cv, "CWAIT");
 
 	device_set_usb_desc(dev);
 
-	snprintf(sc->sc_name, sizeof(sc->sc_name),
-	    "%s", device_get_nameunit(dev));
-
 	DPRINTF("\n");
 
 	/* setup control transfers */
@@ -495,12 +495,32 @@
 	if (sc->sc_modetable) {
 		free(sc->sc_modetable, M_USBDEV);
 	}
-	mtx_destroy(&sc->sc_mtx);
 	cv_destroy(&sc->sc_cv);
 
+	device_claim_softc(dev);
+
+	ufoma_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(ufoma);
+
+static void
+ufoma_free_softc(struct ufoma_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+ufoma_free(struct ucom_softc *ucom)
+{
+	ufoma_free_softc(ucom->sc_parent);
+}
+
 static void *
 ufoma_get_intconf(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id,
     uint8_t type, uint8_t subtype)
@@ -611,10 +631,7 @@
 
 		if (error == USB_ERR_CANCELLED) {
 			return;
-		} else {
-			goto tr_setup;
 		}
-
 		goto tr_transferred;
 	}
 }
@@ -631,7 +648,6 @@
 	case USB_ST_TRANSFERRED:
 tr_transferred:
 	case USB_ST_SETUP:
-tr_setup:
 		pc = usbd_xfer_get_frame(xfer, 1);
 		if (ucom_get_data(&sc->sc_ucom, pc, 0, 1, &actlen)) {
 
@@ -657,10 +673,7 @@
 
 		if (error == USB_ERR_CANCELLED) {
 			return;
-		} else {
-			goto tr_setup;
 		}
-
 		goto tr_transferred;
 	}
 }

Modified: trunk/sys/dev/usb/serial/uftdi.c
===================================================================
--- trunk/sys/dev/usb/serial/uftdi.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uftdi.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -75,7 +75,7 @@
 #ifdef USB_DEBUG
 static int uftdi_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
 SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW,
     &uftdi_debug, 0, "Debug level");
 #endif
@@ -110,8 +110,6 @@
 	uint8_t	sc_hdrlen;
 	uint8_t	sc_msr;
 	uint8_t	sc_lsr;
-
-	uint8_t	sc_name[16];
 };
 
 struct uftdi_param_config {
@@ -127,10 +125,12 @@
 static device_probe_t uftdi_probe;
 static device_attach_t uftdi_attach;
 static device_detach_t uftdi_detach;
+static void uftdi_free_softc(struct uftdi_softc *);
 
 static usb_callback_t uftdi_write_callback;
 static usb_callback_t uftdi_read_callback;
 
+static void	uftdi_free(struct ucom_softc *);
 static void	uftdi_cfg_open(struct ucom_softc *);
 static void	uftdi_cfg_set_dtr(struct ucom_softc *, uint8_t);
 static void	uftdi_cfg_set_rts(struct ucom_softc *, uint8_t);
@@ -182,6 +182,7 @@
 	.ucom_start_write = &uftdi_start_write,
 	.ucom_stop_write = &uftdi_stop_write,
 	.ucom_poll = &uftdi_poll,
+	.ucom_free = &uftdi_free,
 };
 
 static device_method_t uftdi_methods[] = {
@@ -189,7 +190,6 @@
 	DEVMETHOD(device_probe, uftdi_probe),
 	DEVMETHOD(device_attach, uftdi_attach),
 	DEVMETHOD(device_detach, uftdi_detach),
-
 	DEVMETHOD_END
 };
 
@@ -209,53 +209,638 @@
 static const STRUCT_USB_HOST_ID uftdi_devs[] = {
 #define	UFTDI_DEV(v, p, i) \
   { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
+	UFTDI_DEV(ACTON, SPECTRAPRO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ALTI2, N3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ANALOGDEVICES, GNICE, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(ANALOGDEVICES, GNICEPLUS, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
 	UFTDI_DEV(ATMEL, STK541, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(BAYER, CONTOUR_CABLE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, 232USB9M, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, 485USB9F_2W, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, 485USB9F_4W, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, 485USBTB_2W, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, 485USBTB_4W, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, TTL3USB9M, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, TTL5USB9M, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USO9ML2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USO9ML2DR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USO9ML2DR_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USOPTL4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USOPTL4DR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USOPTL4DR2, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(BBELECTRONICS, USOTL4, UFTDI_TYPE_8U232AM),
-	UFTDI_DEV(DRESDENELEKTRONIK, SENSORTERMINALBOARD,
-	    UFTDI_TYPE_8U232AM),
-	UFTDI_DEV(DRESDENELEKTRONIK, WIRELESSHANDHELDTERMINAL,
-	    UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(BBELECTRONICS, USPTL4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, USTL4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(BBELECTRONICS, ZZ_PROG1_USB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(CONTEC, COM1USBH, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(DRESDENELEKTRONIK, SENSORTERMINALBOARD, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(DRESDENELEKTRONIK, WIRELESSHANDHELDTERMINAL, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(ELEKTOR, FT323R, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(EVOLUTION, ER1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(EVOLUTION, HYBRID, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(EVOLUTION, RCM4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FALCOM, SAMBA, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FALCOM, TWIST, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FIC, NEO1973_DEBUG, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FIC, NEO1973_DEBUG, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, 232H, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, 232RL, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, 4N_GALAXY_DE_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, 4N_GALAXY_DE_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, 4N_GALAXY_DE_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, 8U232AM_ALT, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ACCESSO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ACG_HFDUAL, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ACTIVE_ROBOTS, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ACTZWAVE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, AMC232, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ARTEMIS, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ASK_RDR400, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ATIK_ATK16, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ATIK_ATK16C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ATIK_ATK16HR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ATIK_ATK16HRC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ATIK_ATK16IC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, BCS_SE923, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, BEAGLEBONE, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, CANDAPTER, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CANUSB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CCSICDU20_0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CCSICDU40_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CCSICDU64_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CCSLOAD_N_GO_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CCSMACHX_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CCSPRIME8_5, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, CFA_631, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, CFA_632, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, CFA_633, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, CFA_634, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, CFA_635, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, CHAMSYS_24_MASTER_WING, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_MAXI_WING, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_MEDIA_WING, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_MIDI_TIMECODE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_MINI_WING, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_PC_WING, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_USB_DMX, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CHAMSYS_WING, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, COM4SM, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, CONVERTER_7, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, CTI_USB_MINI_485, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, CTI_USB_NANO_485, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, DMX4ALL, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, DOMINTELL_DGQG, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, DOMINTELL_DUSB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, DOTEC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ECLO_COM_1WIRE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ECO_PRO_CDS, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, EISCOU, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, ELSTER_UNICOM, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_ALC8500, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_CLI7000, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_CSI8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_EC3000, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_EM1000DL, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_EM1010PC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_FEM, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_FHZ1000PC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_FHZ1300PC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_FM3RX, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_FS20SIG, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_HS485, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_KL100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_MSM1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_PCD200, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_PCK100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_PPS7330, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_RFP500, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_T1100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_TFD128, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_TFM100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_TWS550, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UAD8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UDA7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UDF77, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UIO88, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_ULA200, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UM100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UMS100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UO100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UR100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_USI2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_USR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_UTP8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_WS300PC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_WS444PC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_WS500, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_WS550, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_WS777, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, ELV_WS888, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, EMCU2D, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, EMCU2H, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, FUTURE_0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, FUTURE_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, FUTURE_2, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, GAMMASCOUT, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, GENERIC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E808, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E809, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E80A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E80B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E80C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E80D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E80E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E80F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E88D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E88E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, GUDEADS_E88F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, HD_RADIO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, HO720, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, HO730, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, HO820, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, HO870, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_APP70, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_PCMCIA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_PEDO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_PICPRO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_PK1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_PROD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_RS232MON, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IBS_US485, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IPLUS, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IPLUS2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, IRTRANS, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, KBS, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, KTLINK, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, LENZ_LIUSB, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, LK202, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, LK204, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, LM3S_DEVEL_BOARD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, LM3S_EVAL_BOARD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, MASTERDEVEL2, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, MAXSTREAM, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, MHAM_DB9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_IC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_KW, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_RS232, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_Y6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_Y8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_Y9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MHAM_YS, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MICRO_CHAMELEON, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MTXORB_5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, MTXORB_6, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, MX2_3, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, MX4_5, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, NXTCAM, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, OCEANIC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, OOCDLINK, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, OPENDCC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, OPENDCC_GATEWAY, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, OPENDCC_GBM, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, OPENDCC_SNIFFER, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, OPENDCC_THROTTLE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, PCDJ_DAC2, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, PCMSFU, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, PERLE_ULTRAPORT, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, PHI_FISCO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, PIEGROUP, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, PROPOX_JTAGCABLEII, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, R2000KU_TRUE_RNG, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, R2X0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, RELAIS, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, REU_TINY, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, RMP200, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, RM_CANVIEW, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, RRCIRKITS_LOCOBUFFER, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCIENCESCOPE_HS_LOGBOOK, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCIENCESCOPE_LOGBOOKML, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCIENCESCOPE_LS_LOGBOOK, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SCS_DEVICE_7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SDMUSBQSS, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, SEMC_DSS20, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, SERIAL_2232C, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, SERIAL_2232D, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, SERIAL_232RL, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, SERIAL_4232H, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, SERIAL_8U100AX, UFTDI_TYPE_SIO),
 	UFTDI_DEV(FTDI, SERIAL_8U232AM, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, SERIAL_8U232AM4, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, SIGNALYZER_SH2, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, SIGNALYZER_SH4, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, SIGNALYZER_SLITE, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, SIGNALYZER_ST, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(FTDI, SPECIAL_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SPECIAL_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SPECIAL_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SPROG_II, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SR_RADIO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, SUUNTO_SPORTS, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, TAVIR_STK500, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, TERATRONIK_D2XX, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, TERATRONIK_VCP, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, THORLABS, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, TNC_X, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, TTUSB, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, TURTELIZER2, UFTDI_TYPE_8U232AM | UFTDI_FLAG_JTAG),
 	UFTDI_DEV(FTDI, UOPTBR, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(FTDI, USBSERIAL, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, USBX_707, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(FTDI, USB_UIRT, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(FTDI, USINT_CAT, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, USINT_RS232, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, USINT_WKEY, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, VARDAAN, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, VNHCPCUSB_D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, WESTREX_MODEL_777, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, WESTREX_MODEL_8900F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, XF_547, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, XF_640, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, XF_642, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, XM_RADIO, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(FTDI, YEI_SERVOCENTER31, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(GNOTOMETRICS, USB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, SP1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, OPC_U_UC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2C1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2C2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2KVR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2KVT, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2VR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP2VT, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP4KVR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(ICOM, RP4KVT, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(IDTECH, IDT1221U, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(INTERBIOMETRICS, IOBOARD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(INTERBIOMETRICS, MINI_IOBOARD, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(INTREPIDCS, NEOVI, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(INTREPIDCS, VALUECAN, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(IONICS, PLUGCOMPUTER, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(JETI, SPC1201, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(KOBIL, CONV_B1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(KOBIL, CONV_KAAN, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(LARSENBRUSGAARD, ALTITRACK, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(MARVELL, SHEEVAPLUG, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0100, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0101, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0102, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0103, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0104, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0105, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0106, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0107, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0108, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0109, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0110, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0111, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0112, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0113, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0114, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0115, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0116, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0117, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0118, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0119, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0120, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0121, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0122, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0123, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0124, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0125, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0126, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0128, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0129, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0130, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0131, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0132, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0133, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0134, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0135, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0136, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0137, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0138, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0139, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0140, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0141, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0142, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0143, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0144, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0145, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0146, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0147, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0148, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0149, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0150, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0151, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0152, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0159, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0160, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0161, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0162, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0163, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0164, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0165, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0166, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0167, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0168, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0169, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0170, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0171, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0172, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0173, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0174, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0175, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0176, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0177, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0178, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0179, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0180, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0181, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0182, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0183, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0184, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0185, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0186, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0187, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0188, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0189, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0190, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0191, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0192, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0193, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0194, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0195, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0196, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0197, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0198, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0199, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019A, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019D, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019E, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019F, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AF, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BF, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CF, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DF, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01ED, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EF, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F0, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F9, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FA, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FD, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FF, UFTDI_TYPE_AUTO),
 	UFTDI_DEV(MATRIXORBITAL, MOUA, UFTDI_TYPE_8U232AM),
 	UFTDI_DEV(MELCO, PCOPRS1, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(METAGEEK, TELLSTICK, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(MOBILITY, USB_SERIAL, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(OLIMEX, ARM_USB_OCD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(OLIMEX, ARM_USB_OCD_H, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
+	UFTDI_DEV(OPTO, CRD7734, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(OPTO, CRD7734_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, AD4USB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, AP485, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, AP485_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, DRAK5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, DRAK6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, GMSR, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, GMUX, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, IRAMP, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, LEC, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, MU, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO10X1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO2X16, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO2X2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO30X3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO3X32, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO4X4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO60X3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, QUIDO8X8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB232, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB422, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB422_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB485, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB485C, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB485S, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SB485_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, SIMUKEY, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, TMU, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(PAPOUCH, UPSUSB, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(POSIFLEX, PP7000, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(QIHARDWARE, JTAGSERIAL, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
 	UFTDI_DEV(RATOC, REXUSB60F, UFTDI_TYPE_8U232AM),
-	UFTDI_DEV(SIIG2, US2308, UFTDI_TYPE_8U232AM)
+	UFTDI_DEV(RTSYSTEMS, CT29B, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(RTSYSTEMS, SERIAL_VX7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2101, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2102, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2103, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2104, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2106, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2201_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2201_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2202_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2202_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2203_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2203_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2401_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2401_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2401_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2401_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2402_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2402_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2402_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2402_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2403_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2403_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2403_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2403_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2801_8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2802_8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_1, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_2, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_3, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_4, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_5, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_6, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_7, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SEALEVEL, 2803_8, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SIIG2, DK201, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(SIIG2, US2308, UFTDI_TYPE_8U232AM),
+	UFTDI_DEV(TESTO, USB_INTERFACE, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(TML, USB_SERIAL, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(TTI, QL355P, UFTDI_TYPE_AUTO),
+	UFTDI_DEV(UNKNOWN4, NF_RIC, UFTDI_TYPE_AUTO),
 #undef UFTDI_DEV
 };
 
@@ -304,10 +889,8 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uftdi", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
-	snprintf(sc->sc_name, sizeof(sc->sc_name),
-	    "%s", device_get_nameunit(dev));
-
 	DPRINTF("\n");
 
 	sc->sc_iface_index = uaa->info.bIfaceIndex;
@@ -314,6 +897,17 @@
 	sc->sc_type = USB_GET_DRIVER_INFO(uaa) & UFTDI_TYPE_MASK;
 
 	switch (sc->sc_type) {
+	case UFTDI_TYPE_AUTO:
+		/* simplified type check */
+		if (uaa->info.bcdDevice >= 0x0200 ||
+		    usbd_get_iface(uaa->device, 1) != NULL) {
+			sc->sc_type = UFTDI_TYPE_8U232AM;
+			sc->sc_hdrlen = 0;
+		} else {
+			sc->sc_type = UFTDI_TYPE_SIO;
+			sc->sc_hdrlen = 1;
+		}
+		break;
 	case UFTDI_TYPE_SIO:
 		sc->sc_hdrlen = 1;
 		break;
@@ -368,12 +962,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uftdi_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uftdi);
+
 static void
+uftdi_free_softc(struct uftdi_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uftdi_free(struct ucom_softc *ucom)
+{
+	uftdi_free_softc(ucom->sc_parent);
+}
+
+static void
 uftdi_cfg_open(struct ucom_softc *ucom)
 {
 	struct uftdi_softc *sc = ucom->sc_parent;

Modified: trunk/sys/dev/usb/serial/uftdi_reg.h
===================================================================
--- trunk/sys/dev/usb/serial/uftdi_reg.h	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uftdi_reg.h	2013-12-28 15:28:46 UTC (rev 6568)
@@ -39,6 +39,7 @@
 #define	UFTDI_TYPE_MASK		0x000000ff
 #define	UFTDI_TYPE_SIO		0x00000001
 #define	UFTDI_TYPE_8U232AM	0x00000002
+#define	UFTDI_TYPE_AUTO		(UFTDI_TYPE_SIO | UFTDI_TYPE_8U232AM)
 #define	UFTDI_FLAG_MASK		0x0000ff00
 #define	UFTDI_FLAG_JTAG		0x00000100
 
@@ -175,7 +176,7 @@
  *   BmRequestType:  0100 0000b
  *   bRequest:       FTDI_SIO_SET_FLOW_CTRL
  *   wValue:         Xoff/Xon
- *   wIndex:         Protocol/Port - hIndex is protocl / lIndex is port
+ *   wIndex:         Protocol/Port - hIndex is protocol / lIndex is port
  *   wLength:        0
  *   Data:           None
  *

Modified: trunk/sys/dev/usb/serial/ugensa.c
===================================================================
--- trunk/sys/dev/usb/serial/ugensa.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/ugensa.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -94,10 +94,12 @@
 static device_probe_t ugensa_probe;
 static device_attach_t ugensa_attach;
 static device_detach_t ugensa_detach;
+static void ugensa_free_softc(struct ugensa_softc *);
 
 static usb_callback_t ugensa_bulk_write_callback;
 static usb_callback_t ugensa_bulk_read_callback;
 
+static void	ugensa_free(struct ucom_softc *);
 static void	ugensa_start_read(struct ucom_softc *);
 static void	ugensa_stop_read(struct ucom_softc *);
 static void	ugensa_start_write(struct ucom_softc *);
@@ -131,6 +133,7 @@
 	.ucom_start_write = &ugensa_start_write,
 	.ucom_stop_write = &ugensa_stop_write,
 	.ucom_poll = &ugensa_poll,
+	.ucom_free = &ugensa_free,
 };
 
 static device_method_t ugensa_methods[] = {
@@ -138,7 +141,7 @@
 	DEVMETHOD(device_probe, ugensa_probe),
 	DEVMETHOD(device_attach, ugensa_attach),
 	DEVMETHOD(device_detach, ugensa_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t ugensa_devclass;
@@ -192,6 +195,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "ugensa", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	/* Figure out how many interfaces this device has got */
 	for (cnt = 0; cnt < UGENSA_IFACE_MAX; cnt++) {
@@ -266,12 +270,32 @@
 	for (x = 0; x < sc->sc_niface; x++) {
 		usbd_transfer_unsetup(sc->sc_sub[x].sc_xfer, UGENSA_N_TRANSFER);
 	}
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	ugensa_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(ugensa);
+
 static void
+ugensa_free_softc(struct ugensa_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+ugensa_free(struct ucom_softc *ucom)
+{
+	ugensa_free_softc(ucom->sc_parent);
+}
+
+static void
 ugensa_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct ugensa_sub_softc *ssc = usbd_xfer_softc(xfer);

Modified: trunk/sys/dev/usb/serial/uipaq.c
===================================================================
--- trunk/sys/dev/usb/serial/uipaq.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uipaq.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -103,10 +103,12 @@
 static device_probe_t uipaq_probe;
 static device_attach_t uipaq_attach;
 static device_detach_t uipaq_detach;
+static void uipaq_free_softc(struct uipaq_softc *);
 
 static usb_callback_t uipaq_write_callback;
 static usb_callback_t uipaq_read_callback;
 
+static void	uipaq_free(struct ucom_softc *);
 static void	uipaq_start_read(struct ucom_softc *);
 static void	uipaq_stop_read(struct ucom_softc *);
 static void	uipaq_start_write(struct ucom_softc *);
@@ -146,6 +148,7 @@
 	.ucom_start_write = &uipaq_start_write,
 	.ucom_stop_write = &uipaq_stop_write,
 	.ucom_poll = &uipaq_poll,
+	.ucom_free = &uipaq_free,
 };
 
 /*
@@ -1070,7 +1073,7 @@
 	DEVMETHOD(device_probe, uipaq_probe),
 	DEVMETHOD(device_attach, uipaq_attach),
 	DEVMETHOD(device_detach, uipaq_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t uipaq_devclass;
@@ -1121,6 +1124,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uipaq", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	/*
 	 * Send magic bytes, cribbed from Linux ipaq driver that
@@ -1176,12 +1180,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UIPAQ_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uipaq_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uipaq);
+
 static void
+uipaq_free_softc(struct uipaq_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uipaq_free(struct ucom_softc *ucom)
+{
+	uipaq_free_softc(ucom->sc_parent);
+}
+
+static void
 uipaq_start_read(struct ucom_softc *ucom)
 {
 	struct uipaq_softc *sc = ucom->sc_parent;

Modified: trunk/sys/dev/usb/serial/ulpt.c
===================================================================
--- trunk/sys/dev/usb/serial/ulpt.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/ulpt.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -74,7 +74,7 @@
 #ifdef USB_DEBUG
 static int ulpt_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ulpt, CTLFLAG_RW, 0, "USB ulpt");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ulpt, CTLFLAG_RW, 0, "USB ulpt");
 SYSCTL_INT(_hw_usb_ulpt, OID_AUTO, debug, CTLFLAG_RW,
     &ulpt_debug, 0, "Debug level");
 #endif
@@ -747,7 +747,7 @@
 	DEVMETHOD(device_probe, ulpt_probe),
 	DEVMETHOD(device_attach, ulpt_attach),
 	DEVMETHOD(device_detach, ulpt_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static driver_t ulpt_driver = {

Modified: trunk/sys/dev/usb/serial/umcs.c
===================================================================
--- trunk/sys/dev/usb/serial/umcs.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/umcs.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -79,7 +79,7 @@
 #ifdef USB_DEBUG
 static int umcs_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, umcs, CTLFLAG_RW, 0, "USB umcs quadport serial adapter");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, umcs, CTLFLAG_RW, 0, "USB umcs quadport serial adapter");
 SYSCTL_INT(_hw_usb_umcs, OID_AUTO, debug, CTLFLAG_RW, &umcs_debug, 0, "Debug level");
 #endif					/* USB_DEBUG */
 
@@ -154,6 +154,7 @@
 static usb_error_t umcs7840_set_baudrate(struct umcs7840_softc *, uint8_t, uint32_t);
 static usb_error_t umcs7840_calc_baudrate(uint32_t rate, uint16_t *, uint8_t *);
 
+static void	umcs7840_free(struct ucom_softc *);
 static void umcs7840_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
 static void umcs7840_cfg_set_dtr(struct ucom_softc *, uint8_t);
 static void umcs7840_cfg_set_rts(struct ucom_softc *, uint8_t);
@@ -175,6 +176,7 @@
 static device_probe_t umcs7840_probe;
 static device_attach_t umcs7840_attach;
 static device_detach_t umcs7840_detach;
+static void umcs7840_free_softc(struct umcs7840_softc *);
 
 static usb_callback_t umcs7840_intr_callback;
 static usb_callback_t umcs7840_read_callback1;
@@ -251,6 +253,7 @@
 	.ucom_stop_write = &umcs7840_stop_write,
 
 	.ucom_poll = &umcs7840_poll,
+	.ucom_free = &umcs7840_free,
 };
 
 static const STRUCT_USB_HOST_ID umcs7840_devs[] = {
@@ -262,7 +265,7 @@
 	DEVMETHOD(device_probe, umcs7840_probe),
 	DEVMETHOD(device_attach, umcs7840_attach),
 	DEVMETHOD(device_detach, umcs7840_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t umcs7840_devclass;
@@ -310,6 +313,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "umcs7840", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_dev = dev;
 	sc->sc_udev = uaa->device;
@@ -408,11 +412,31 @@
 		usbd_transfer_unsetup(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer, UMCS7840_N_TRANSFERS);
 	usbd_transfer_unsetup(&sc->sc_intr_xfer, 1);
 
-	mtx_destroy(&sc->sc_mtx);
+	device_claim_softc(dev);
+
+	umcs7840_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(umcs7840);
+
 static void
+umcs7840_free_softc(struct umcs7840_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+umcs7840_free(struct ucom_softc *ucom)
+{
+	umcs7840_free_softc(ucom->sc_parent);
+}
+
+static void
 umcs7840_cfg_open(struct ucom_softc *ucom)
 {
 	struct umcs7840_softc *sc = ucom->sc_parent;

Modified: trunk/sys/dev/usb/serial/umct.c
===================================================================
--- trunk/sys/dev/usb/serial/umct.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/umct.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -115,7 +115,6 @@
 	uint8_t	sc_mcr;
 	uint8_t	sc_iface_no;
 	uint8_t sc_swap_cb;
-	uint8_t	sc_name[16];
 };
 
 /* prototypes */
@@ -123,6 +122,7 @@
 static device_probe_t umct_probe;
 static device_attach_t umct_attach;
 static device_detach_t umct_detach;
+static void umct_free_softc(struct umct_softc *);
 
 static usb_callback_t umct_intr_callback;
 static usb_callback_t umct_intr_callback_sub;
@@ -132,6 +132,7 @@
 
 static void	umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
 		    uint16_t len, uint32_t value);
+static void	umct_free(struct ucom_softc *);
 static void	umct_cfg_get_status(struct ucom_softc *, uint8_t *,
 		    uint8_t *);
 static void	umct_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -190,6 +191,7 @@
 	.ucom_start_write = &umct_start_write,
 	.ucom_stop_write = &umct_stop_write,
 	.ucom_poll = &umct_poll,
+	.ucom_free = &umct_free,
 };
 
 static const STRUCT_USB_HOST_ID umct_devs[] = {
@@ -204,7 +206,7 @@
 	DEVMETHOD(device_probe, umct_probe),
 	DEVMETHOD(device_attach, umct_attach),
 	DEVMETHOD(device_detach, umct_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t umct_devclass;
@@ -251,10 +253,8 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "umct", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
-	snprintf(sc->sc_name, sizeof(sc->sc_name),
-	    "%s", device_get_nameunit(dev));
-
 	sc->sc_iface_no = uaa->info.bIfaceNum;
 
 	iface_index = UMCT_IFACE_INDEX;
@@ -312,12 +312,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	umct_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(umct);
+
 static void
+umct_free_softc(struct umct_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+umct_free(struct ucom_softc *ucom)
+{
+	umct_free_softc(ucom->sc_parent);
+}
+
+static void
 umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
     uint16_t len, uint32_t value)
 {

Modified: trunk/sys/dev/usb/serial/umodem.c
===================================================================
--- trunk/sys/dev/usb/serial/umodem.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/umodem.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -118,7 +118,7 @@
 #ifdef USB_DEBUG
 static int umodem_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem");
 SYSCTL_INT(_hw_usb_umodem, OID_AUTO, debug, CTLFLAG_RW,
     &umodem_debug, 0, "Debug level");
 #endif
@@ -139,7 +139,7 @@
 };
 
 /*
- * As speeds for umodem deivces increase, these numbers will need to
+ * As speeds for umodem devices increase, these numbers will need to
  * be increased. They should be good for G3 speeds and below.
  *
  * TODO: The TTY buffers should be increased!
@@ -178,11 +178,13 @@
 static device_probe_t umodem_probe;
 static device_attach_t umodem_attach;
 static device_detach_t umodem_detach;
+static void umodem_free_softc(struct umodem_softc *);
 
 static usb_callback_t umodem_intr_callback;
 static usb_callback_t umodem_write_callback;
 static usb_callback_t umodem_read_callback;
 
+static void	umodem_free(struct ucom_softc *);
 static void	umodem_start_read(struct ucom_softc *);
 static void	umodem_stop_read(struct ucom_softc *);
 static void	umodem_start_write(struct ucom_softc *);
@@ -250,6 +252,7 @@
 	.ucom_start_write = &umodem_start_write,
 	.ucom_stop_write = &umodem_stop_write,
 	.ucom_poll = &umodem_poll,
+	.ucom_free = &umodem_free,
 };
 
 static device_method_t umodem_methods[] = {
@@ -256,7 +259,7 @@
 	DEVMETHOD(device_probe, umodem_probe),
 	DEVMETHOD(device_attach, umodem_attach),
 	DEVMETHOD(device_detach, umodem_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t umodem_devclass;
@@ -302,6 +305,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "umodem", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_ctrl_iface_no = uaa->info.bIfaceNum;
 	sc->sc_iface_index[1] = uaa->info.bIfaceIndex;
@@ -875,12 +879,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UMODEM_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	umodem_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(umodem);
+
 static void
+umodem_free_softc(struct umodem_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+umodem_free(struct ucom_softc *ucom)
+{
+	umodem_free_softc(ucom->sc_parent);
+}
+
+static void
 umodem_poll(struct ucom_softc *ucom)
 {
 	struct umodem_softc *sc = ucom->sc_parent;

Modified: trunk/sys/dev/usb/serial/umoscom.c
===================================================================
--- trunk/sys/dev/usb/serial/umoscom.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/umoscom.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -50,7 +50,7 @@
 #ifdef USB_DEBUG
 static int umoscom_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom");
 SYSCTL_INT(_hw_usb_umoscom, OID_AUTO, debug, CTLFLAG_RW,
     &umoscom_debug, 0, "Debug level");
 #endif
@@ -189,11 +189,13 @@
 static device_probe_t umoscom_probe;
 static device_attach_t umoscom_attach;
 static device_detach_t umoscom_detach;
+static void umoscom_free_softc(struct umoscom_softc *);
 
 static usb_callback_t umoscom_write_callback;
 static usb_callback_t umoscom_read_callback;
 static usb_callback_t umoscom_intr_callback;
 
+static void	umoscom_free(struct ucom_softc *);
 static void	umoscom_cfg_open(struct ucom_softc *);
 static void	umoscom_cfg_close(struct ucom_softc *);
 static void	umoscom_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -258,6 +260,7 @@
 	.ucom_start_write = &umoscom_start_write,
 	.ucom_stop_write = &umoscom_stop_write,
 	.ucom_poll = &umoscom_poll,
+	.ucom_free = &umoscom_free,
 };
 
 static device_method_t umoscom_methods[] = {
@@ -264,7 +267,7 @@
 	DEVMETHOD(device_probe, umoscom_probe),
 	DEVMETHOD(device_attach, umoscom_attach),
 	DEVMETHOD(device_detach, umoscom_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t umoscom_devclass;
@@ -317,6 +320,7 @@
 	device_printf(dev, "<MOSCHIP USB Serial Port Adapter>\n");
 
 	mtx_init(&sc->sc_mtx, "umoscom", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	iface_index = UMOSCOM_IFACE_INDEX;
 	error = usbd_transfer_setup(uaa->device, &iface_index,
@@ -354,12 +358,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UMOSCOM_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	umoscom_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(umoscom);
+
 static void
+umoscom_free_softc(struct umoscom_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+umoscom_free(struct ucom_softc *ucom)
+{
+	umoscom_free_softc(ucom->sc_parent);
+}
+
+static void
 umoscom_cfg_open(struct ucom_softc *ucom)
 {
 	struct umoscom_softc *sc = ucom->sc_parent;

Modified: trunk/sys/dev/usb/serial/uplcom.c
===================================================================
--- trunk/sys/dev/usb/serial/uplcom.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uplcom.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -118,7 +118,7 @@
 #ifdef USB_DEBUG
 static int uplcom_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom");
 SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RW,
     &uplcom_debug, 0, "Debug level");
 #endif
@@ -176,6 +176,7 @@
 static usb_error_t uplcom_pl2303_do(struct usb_device *, int8_t, uint8_t,
 			uint16_t, uint16_t, uint16_t);
 static int	uplcom_pl2303_init(struct usb_device *, uint8_t);
+static void	uplcom_free(struct ucom_softc *);
 static void	uplcom_cfg_set_dtr(struct ucom_softc *, uint8_t);
 static void	uplcom_cfg_set_rts(struct ucom_softc *, uint8_t);
 static void	uplcom_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -192,6 +193,7 @@
 static device_probe_t uplcom_probe;
 static device_attach_t uplcom_attach;
 static device_detach_t uplcom_detach;
+static void uplcom_free_softc(struct uplcom_softc *);
 
 static usb_callback_t uplcom_intr_callback;
 static usb_callback_t uplcom_write_callback;
@@ -242,6 +244,7 @@
 	.ucom_start_write = &uplcom_start_write,
 	.ucom_stop_write = &uplcom_stop_write,
 	.ucom_poll = &uplcom_poll,
+	.ucom_free = &uplcom_free,
 };
 
 #define	UPLCOM_DEV(v,p)				\
@@ -279,6 +282,7 @@
 	UPLCOM_DEV(PROLIFIC, DCU11),		/* DCU-11 Phone Cable */
 	UPLCOM_DEV(PROLIFIC, HCR331),		/* HCR331 Card Reader */
 	UPLCOM_DEV(PROLIFIC, MICROMAX_610U),	/* Micromax 610U modem */
+	UPLCOM_DEV(PROLIFIC, MOTOROLA),		/* Motorola cable */
 	UPLCOM_DEV(PROLIFIC, PHAROS),		/* Prolific Pharos */
 	UPLCOM_DEV(PROLIFIC, PL2303),		/* Generic adapter */
 	UPLCOM_DEV(PROLIFIC, RSAQ2),		/* I/O DATA USB-RSAQ2 */
@@ -314,7 +318,7 @@
 	DEVMETHOD(device_probe, uplcom_probe),
 	DEVMETHOD(device_attach, uplcom_attach),
 	DEVMETHOD(device_detach, uplcom_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t uplcom_devclass;
@@ -363,6 +367,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uplcom", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	DPRINTF("sc = %p\n", sc);
 
@@ -427,12 +432,22 @@
 		    usbd_errstr(error));
 		goto detach;
 	}
-	/* clear stall at first run */
-	mtx_lock(&sc->sc_mtx);
-	usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
-	usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
-	mtx_unlock(&sc->sc_mtx);
 
+	if (sc->sc_chiptype != TYPE_PL2303HX) {
+		/* HX variants seem to lock up after a clear stall request. */
+		mtx_lock(&sc->sc_mtx);
+		usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
+		usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
+		mtx_unlock(&sc->sc_mtx);
+	} else {
+		if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
+		    UPLCOM_SET_REQUEST, 8, 0, 0) ||
+		    uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
+		    UPLCOM_SET_REQUEST, 9, 0, 0)) {
+			goto detach;
+		}
+	}
+
 	error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
 	    &uplcom_callback, &sc->sc_mtx);
 	if (error) {
@@ -464,11 +479,31 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UPLCOM_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uplcom_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uplcom);
+
+static void
+uplcom_free_softc(struct uplcom_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uplcom_free(struct ucom_softc *ucom)
+{
+	uplcom_free_softc(ucom->sc_parent);
+}
+
 static usb_error_t
 uplcom_reset(struct uplcom_softc *sc, struct usb_device *udev)
 {
@@ -530,9 +565,6 @@
 	if (err)
 		return (EIO);
 	
-	if (uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0))
-		return (EIO);
 	return (0);
 }
 

Modified: trunk/sys/dev/usb/serial/usb_serial.c
===================================================================
--- trunk/sys/dev/usb/serial/usb_serial.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/usb_serial.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -101,7 +101,7 @@
 
 #include "opt_gdb.h"
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
 
 #ifdef USB_DEBUG
 static int ucom_debug = 0;
@@ -127,13 +127,13 @@
 static struct ucom_softc *ucom_cons_softc = NULL;
 
 TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit);
-SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW | CTLFLAG_TUN,
     &ucom_cons_unit, 0, "console unit number");
 TUNABLE_INT("hw.usb.ucom.cons_subunit", &ucom_cons_subunit);
-SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW | CTLFLAG_TUN,
     &ucom_cons_subunit, 0, "console subunit number");
 TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud);
-SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW | CTLFLAG_TUN,
     &ucom_cons_baud, 0, "console baud rate");
 
 static usb_proc_callback_t ucom_cfg_start_transfers;
@@ -146,7 +146,7 @@
 static int	ucom_unit_alloc(void);
 static void	ucom_unit_free(int);
 static int	ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
-static void	ucom_detach_tty(struct ucom_softc *);
+static void	ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *);
 static void	ucom_queue_command(struct ucom_softc *,
 		    usb_proc_callback_t *, struct termios *pt,
 		    struct usb_proc_msg *t0, struct usb_proc_msg *t1);
@@ -162,6 +162,7 @@
 static tsw_modem_t ucom_modem;
 static tsw_param_t ucom_param;
 static tsw_outwakeup_t ucom_outwakeup;
+static tsw_inwakeup_t ucom_inwakeup;
 static tsw_free_t ucom_free;
 
 static struct ttydevsw ucom_class = {
@@ -169,6 +170,7 @@
 	.tsw_open = ucom_open,
 	.tsw_close = ucom_close,
 	.tsw_outwakeup = ucom_outwakeup,
+	.tsw_inwakeup = ucom_inwakeup,
 	.tsw_ioctl = ucom_ioctl,
 	.tsw_param = ucom_param,
 	.tsw_modem = ucom_modem,
@@ -178,14 +180,38 @@
 MODULE_DEPEND(ucom, usb, 1, 1, 1);
 MODULE_VERSION(ucom, 1);
 
-#define	UCOM_UNIT_MAX 		128	/* limits size of ucom_bitmap */
+#define	UCOM_UNIT_MAX 		128	/* maximum number of units */
+#define	UCOM_TTY_PREFIX		"U"
 
-static uint8_t ucom_bitmap[(UCOM_UNIT_MAX + 7) / 8];
-static struct mtx ucom_bitmap_mtx;
-MTX_SYSINIT(ucom_bitmap_mtx, &ucom_bitmap_mtx, "ucom bitmap", MTX_DEF);
+static struct unrhdr *ucom_unrhdr;
+static struct mtx ucom_mtx;
+static int ucom_close_refs;
 
-#define UCOM_TTY_PREFIX		"U"
+static void
+ucom_init(void *arg)
+{
+	DPRINTF("\n");
+	ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL);
+	mtx_init(&ucom_mtx, "UCOM MTX", NULL, MTX_DEF);
+}
+SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL);
 
+static void
+ucom_uninit(void *arg)
+{
+	struct unrhdr *hdr;
+	hdr = ucom_unrhdr;
+	ucom_unrhdr = NULL;
+
+	DPRINTF("\n");
+
+	if (hdr != NULL)
+		delete_unrhdr(hdr);
+
+	mtx_destroy(&ucom_mtx);
+}
+SYSUNINIT(ucom_uninit, SI_SUB_KLD - 2, SI_ORDER_ANY, ucom_uninit, NULL);
+
 /*
  * Mark a unit number (the X in cuaUX) as in use.
  *
@@ -197,21 +223,14 @@
 {
 	int unit;
 
-	mtx_lock(&ucom_bitmap_mtx);
-
-	for (unit = 0; unit < UCOM_UNIT_MAX; unit++) {
-		if ((ucom_bitmap[unit / 8] & (1 << (unit % 8))) == 0) {
-			ucom_bitmap[unit / 8] |= (1 << (unit % 8));
-			break;
-		}
+	/* sanity checks */
+	if (ucom_unrhdr == NULL) {
+		DPRINTF("ucom_unrhdr is NULL\n");
+		return (-1);
 	}
-
-	mtx_unlock(&ucom_bitmap_mtx);
-
-	if (unit == UCOM_UNIT_MAX)
-		return -1;
-	else
-		return unit;
+	unit = alloc_unr(ucom_unrhdr);
+	DPRINTF("unit %d is allocated\n", unit);
+	return (unit);
 }
 
 /*
@@ -220,11 +239,13 @@
 static void
 ucom_unit_free(int unit)
 {
-	mtx_lock(&ucom_bitmap_mtx);
-
-	ucom_bitmap[unit / 8] &= ~(1 << (unit % 8));
-
-	mtx_unlock(&ucom_bitmap_mtx);
+	/* sanity checks */
+	if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) {
+		DPRINTF("cannot free unit number\n");
+		return;
+	}
+	DPRINTF("unit %d is freed\n", unit);
+	free_unr(ucom_unrhdr, unit);
 }
 
 /*
@@ -244,7 +265,8 @@
 
 	if ((sc == NULL) ||
 	    (subunits <= 0) ||
-	    (callback == NULL)) {
+	    (callback == NULL) ||
+	    (mtx == NULL)) {
 		return (EINVAL);
 	}
 
@@ -264,7 +286,15 @@
 		return (error);
 	}
 	ssc->sc_subunits = subunits;
+	ssc->sc_flag = UCOM_FLAG_ATTACHED |
+	    UCOM_FLAG_FREE_UNIT;
 
+	if (callback->ucom_free == NULL)
+		ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
+
+	/* increment reference count */
+	ucom_ref(ssc);
+
 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
 		sc[subunit].sc_subunit = subunit;
 		sc[subunit].sc_super = ssc;
@@ -277,6 +307,10 @@
 			ucom_detach(ssc, &sc[0]);
 			return (error);
 		}
+		/* increment reference count */
+		ucom_ref(ssc);
+
+		/* set subunit attached */
 		sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
 	}
 
@@ -287,8 +321,8 @@
 }
 
 /*
- * NOTE: the following function will do nothing if
- * the structure pointed to by "ssc" and "sc" is zero.
+ * The following function will do nothing if the structure pointed to
+ * by "ssc" and "sc" is zero or has already been detached.
  */
 void
 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
@@ -295,7 +329,7 @@
 {
 	int subunit;
 
-	if (ssc->sc_subunits == 0)
+	if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
 		return;		/* not initialized */
 
 	if (ssc->sc_sysctl_ttyname != NULL) {
@@ -313,16 +347,46 @@
 	for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
 		if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
 
-			ucom_detach_tty(&sc[subunit]);
+			ucom_detach_tty(ssc, &sc[subunit]);
 
 			/* avoid duplicate detach */
 			sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
 		}
 	}
-	ucom_unit_free(ssc->sc_unit);
 	usb_proc_free(&ssc->sc_tq);
+
+	ucom_unref(ssc);
+
+	if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
+		ucom_drain(ssc);
+
+	/* make sure we don't detach twice */
+	ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
 }
 
+void
+ucom_drain(struct ucom_super_softc *ssc)
+{
+	mtx_lock(&ucom_mtx);
+	while (ssc->sc_refs > 0) {
+		printf("ucom: Waiting for a TTY device to close.\n");
+		usb_pause_mtx(&ucom_mtx, hz);
+	}
+	mtx_unlock(&ucom_mtx);
+}
+
+void
+ucom_drain_all(void *arg)
+{
+	mtx_lock(&ucom_mtx);
+	while (ucom_close_refs > 0) {
+		printf("ucom: Waiting for all detached TTY "
+		    "devices to have open fds closed.\n");
+		usb_pause_mtx(&ucom_mtx, hz);
+	}
+	mtx_unlock(&ucom_mtx);
+}
+
 static int
 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
 {
@@ -356,24 +420,20 @@
 	sc->sc_tty = tp;
 
 	DPRINTF("ttycreate: %s\n", buf);
-	cv_init(&sc->sc_cv, "ucom");
 
 	/* Check if this device should be a console */
 	if ((ucom_cons_softc == NULL) && 
 	    (ssc->sc_unit == ucom_cons_unit) &&
 	    (sc->sc_subunit == ucom_cons_subunit)) {
-		struct termios t;
 
-		DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit);
+		DPRINTF("unit %d subunit %d is console",
+		    ssc->sc_unit, sc->sc_subunit);
 
 		ucom_cons_softc = sc;
 
-		memset(&t, 0, sizeof(t));
-		t.c_ispeed = ucom_cons_baud;
-		t.c_ospeed = t.c_ispeed;
-		t.c_cflag = CS8;
+		tty_init_console(tp, ucom_cons_baud);
 
-		mtx_lock(ucom_cons_softc->sc_mtx);
+		UCOM_MTX_LOCK(ucom_cons_softc);
 		ucom_cons_rx_low = 0;
 		ucom_cons_rx_high = 0;
 		ucom_cons_tx_low = 0;
@@ -380,8 +440,8 @@
 		ucom_cons_tx_high = 0;
 		sc->sc_flag |= UCOM_FLAG_CONSOLE;
 		ucom_open(ucom_cons_softc->sc_tty);
-		ucom_param(ucom_cons_softc->sc_tty, &t);
-		mtx_unlock(ucom_cons_softc->sc_mtx);
+		ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in);
+		UCOM_MTX_UNLOCK(ucom_cons_softc);
 	}
 
 	return (0);
@@ -388,7 +448,7 @@
 }
 
 static void
-ucom_detach_tty(struct ucom_softc *sc)
+ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
 {
 	struct tty *tp = sc->sc_tty;
 
@@ -395,20 +455,25 @@
 	DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
 
 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
-		mtx_lock(ucom_cons_softc->sc_mtx);
+		UCOM_MTX_LOCK(ucom_cons_softc);
 		ucom_close(ucom_cons_softc->sc_tty);
 		sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
-		mtx_unlock(ucom_cons_softc->sc_mtx);
+		UCOM_MTX_UNLOCK(ucom_cons_softc);
 		ucom_cons_softc = NULL;
 	}
 
 	/* the config thread has been stopped when we get here */
 
-	mtx_lock(sc->sc_mtx);
+	UCOM_MTX_LOCK(sc);
 	sc->sc_flag |= UCOM_FLAG_GONE;
 	sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
-	mtx_unlock(sc->sc_mtx);
+	UCOM_MTX_UNLOCK(sc);
+
 	if (tp) {
+		mtx_lock(&ucom_mtx);
+		ucom_close_refs++;
+		mtx_unlock(&ucom_mtx);
+
 		tty_lock(tp);
 
 		ucom_close(tp);	/* close, if any */
@@ -415,22 +480,16 @@
 
 		tty_rel_gone(tp);
 
-		mtx_lock(sc->sc_mtx);
-		/* Wait for the callback after the TTY is torn down */
-		while (sc->sc_ttyfreed == 0)
-			cv_wait(&sc->sc_cv, sc->sc_mtx);
+		UCOM_MTX_LOCK(sc);
 		/*
 		 * make sure that read and write transfers are stopped
 		 */
-		if (sc->sc_callback->ucom_stop_read) {
+		if (sc->sc_callback->ucom_stop_read)
 			(sc->sc_callback->ucom_stop_read) (sc);
-		}
-		if (sc->sc_callback->ucom_stop_write) {
+		if (sc->sc_callback->ucom_stop_write)
 			(sc->sc_callback->ucom_stop_write) (sc);
-		}
-		mtx_unlock(sc->sc_mtx);
+		UCOM_MTX_UNLOCK(sc);
 	}
-	cv_destroy(&sc->sc_cv);
 }
 
 void
@@ -476,7 +535,7 @@
 	struct ucom_super_softc *ssc = sc->sc_super;
 	struct ucom_param_task *task;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (usb_proc_is_gone(&ssc->sc_tq)) {
 		DPRINTF("proc is gone\n");
@@ -520,7 +579,7 @@
 {
 	struct tty *tp = sc->sc_tty;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	DPRINTF("\n");
 
@@ -621,7 +680,7 @@
 	struct ucom_softc *sc = tty_softc(tp);
 	int error;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (sc->sc_flag & UCOM_FLAG_GONE) {
 		return (ENXIO);
@@ -656,6 +715,10 @@
 	sc->sc_pls_set = 0;
 	sc->sc_pls_clr = 0;
 
+	/* reset jitter buffer */
+	sc->sc_jitterbuf_in = 0;
+	sc->sc_jitterbuf_out = 0;
+
 	ucom_queue_command(sc, ucom_cfg_open, NULL,
 	    &sc->sc_open_task[0].hdr,
 	    &sc->sc_open_task[1].hdr);
@@ -699,7 +762,7 @@
 {
 	struct ucom_softc *sc = tty_softc(tp);
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	DPRINTF("tp=%p\n", tp);
 
@@ -720,6 +783,52 @@
 	}
 }
 
+static void
+ucom_inwakeup(struct tty *tp)
+{
+	struct ucom_softc *sc = tty_softc(tp);
+	uint16_t pos;
+
+	if (sc == NULL)
+		return;
+
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
+
+	DPRINTF("tp=%p\n", tp);
+
+	if (ttydisc_can_bypass(tp) != 0 || 
+	    (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
+	    (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
+		return;
+	}
+
+	/* prevent recursion */
+	sc->sc_flag |= UCOM_FLAG_INWAKEUP;
+
+	pos = sc->sc_jitterbuf_out;
+
+	while (sc->sc_jitterbuf_in != pos) {
+		int c;
+
+		c = (char)sc->sc_jitterbuf[pos];
+
+		if (ttydisc_rint(tp, c, 0) == -1)
+			break;
+		pos++;
+		if (pos >= UCOM_JITTERBUF_SIZE)
+			pos -= UCOM_JITTERBUF_SIZE;
+	}
+
+	sc->sc_jitterbuf_out = pos;
+
+	/* clear RTS in async fashion */
+	if ((sc->sc_jitterbuf_in == pos) && 
+	    (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
+		ucom_rts(sc, 0);
+
+	sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
+}
+
 static int
 ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
 {
@@ -726,7 +835,7 @@
 	struct ucom_softc *sc = tty_softc(tp);
 	int error;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
 		return (EIO);
@@ -770,7 +879,7 @@
 	struct ucom_softc *sc = tty_softc(tp);
 	uint8_t onoff;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
 		return (0);
@@ -889,7 +998,7 @@
 ucom_line_state(struct ucom_softc *sc,
     uint8_t set_bits, uint8_t clear_bits)
 {
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
 		return;
@@ -967,7 +1076,7 @@
 
 	tp = sc->sc_tty;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
 		return;
@@ -1029,7 +1138,7 @@
 void
 ucom_status_change(struct ucom_softc *sc)
 {
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (sc->sc_flag & UCOM_FLAG_CONSOLE)
 		return;		/* not supported */
@@ -1071,7 +1180,7 @@
 	uint8_t opened;
 	int error;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	opened = 0;
 	error = 0;
@@ -1079,11 +1188,15 @@
 	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
 
 		/* XXX the TTY layer should call "open()" first! */
-
+		/*
+		 * Not quite: Its ordering is partly backwards, but
+		 * some parameters must be set early in ttydev_open(),
+		 * possibly before calling ttydevsw_open().
+		 */
 		error = ucom_open(tp);
-		if (error) {
+		if (error)
 			goto done;
-		}
+
 		opened = 1;
 	}
 	DPRINTF("sc = %p\n", sc);
@@ -1090,6 +1203,7 @@
 
 	/* Check requested parameters. */
 	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
+		/* XXX c_ospeed == 0 is perfectly valid. */
 		DPRINTF("mismatch ispeed and ospeed\n");
 		error = EINVAL;
 		goto done;
@@ -1138,7 +1252,7 @@
 {
 	struct ucom_softc *sc = tty_softc(tp);
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	DPRINTF("sc = %p\n", sc);
 
@@ -1165,7 +1279,7 @@
 	uint32_t cnt;
 	uint32_t offset_orig;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
 		unsigned int temp;
@@ -1244,7 +1358,7 @@
 	char *buf;
 	uint32_t cnt;
 
-	mtx_assert(sc->sc_mtx, MA_OWNED);
+	UCOM_MTX_ASSERT(sc, MA_OWNED);
 
 	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
 		unsigned int temp;
@@ -1300,6 +1414,11 @@
 		/* first check if we can pass the buffer directly */
 
 		if (ttydisc_can_bypass(tp)) {
+
+			/* clear any jitter buffer */
+			sc->sc_jitterbuf_in = 0;
+			sc->sc_jitterbuf_out = 0;
+
 			if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
 				DPRINTF("tp=%p, data lost\n", tp);
 			}
@@ -1308,9 +1427,32 @@
 		/* need to loop */
 
 		for (cnt = 0; cnt != res.length; cnt++) {
-			if (ttydisc_rint(tp, buf[cnt], 0) == -1) {
-				/* XXX what should we do? */
+			if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
+			    ttydisc_rint(tp, buf[cnt], 0) == -1) {
+				uint16_t end;
+				uint16_t pos;
 
+				pos = sc->sc_jitterbuf_in;
+				end = sc->sc_jitterbuf_out +
+				    UCOM_JITTERBUF_SIZE - 1;
+				if (end >= UCOM_JITTERBUF_SIZE)
+					end -= UCOM_JITTERBUF_SIZE;
+
+				for (; cnt != res.length; cnt++) {
+					if (pos == end)
+						break;
+					sc->sc_jitterbuf[pos] = buf[cnt];
+					pos++;
+					if (pos >= UCOM_JITTERBUF_SIZE)
+						pos -= UCOM_JITTERBUF_SIZE;
+				}
+
+				sc->sc_jitterbuf_in = pos;
+
+				/* set RTS in async fashion */
+				if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
+					ucom_rts(sc, 1);
+
 				DPRINTF("tp=%p, lost %d "
 				    "chars\n", tp, res.length - cnt);
 				break;
@@ -1325,10 +1467,14 @@
 {
 	struct ucom_softc *sc = xsc;
 
-	mtx_lock(sc->sc_mtx);
-	sc->sc_ttyfreed = 1;
-	cv_signal(&sc->sc_cv);
-	mtx_unlock(sc->sc_mtx);
+	if (sc->sc_callback->ucom_free != NULL)
+		sc->sc_callback->ucom_free(sc);
+	else
+		ucom_unref(sc->sc_super);
+
+	mtx_lock(&ucom_mtx);
+	ucom_close_refs--;
+	mtx_unlock(&ucom_mtx);
 }
 
 static cn_probe_t ucom_cnprobe;
@@ -1381,7 +1527,7 @@
 	if (sc == NULL)
 		return (-1);
 
-	mtx_lock(sc->sc_mtx);
+	UCOM_MTX_LOCK(sc);
 
 	if (ucom_cons_rx_low != ucom_cons_rx_high) {
 		c = ucom_cons_rx_buf[ucom_cons_rx_low];
@@ -1394,7 +1540,7 @@
 	/* start USB transfers */
 	ucom_outwakeup(sc->sc_tty);
 
-	mtx_unlock(sc->sc_mtx);
+	UCOM_MTX_UNLOCK(sc);
 
 	/* poll if necessary */
 	if (kdb_active && sc->sc_callback->ucom_poll)
@@ -1414,7 +1560,7 @@
 
  repeat:
 
-	mtx_lock(sc->sc_mtx);
+	UCOM_MTX_LOCK(sc);
 
 	/* compute maximum TX length */
 
@@ -1430,7 +1576,7 @@
 	/* start USB transfers */
 	ucom_outwakeup(sc->sc_tty);
 
-	mtx_unlock(sc->sc_mtx);
+	UCOM_MTX_UNLOCK(sc);
 
 	/* poll if necessary */
 	if (kdb_active && sc->sc_callback->ucom_poll) {
@@ -1441,6 +1587,62 @@
 	}
 }
 
+/*------------------------------------------------------------------------*
+ *	ucom_ref
+ *
+ * This function will increment the super UCOM reference count.
+ *------------------------------------------------------------------------*/
+void
+ucom_ref(struct ucom_super_softc *ssc)
+{
+	mtx_lock(&ucom_mtx);
+	ssc->sc_refs++;
+	mtx_unlock(&ucom_mtx);
+}
+
+/*------------------------------------------------------------------------*
+ *	ucom_free_unit
+ *
+ * This function will free the super UCOM's allocated unit
+ * number. This function can be called on a zero-initialized
+ * structure. This function can be called multiple times.
+ *------------------------------------------------------------------------*/
+static void
+ucom_free_unit(struct ucom_super_softc *ssc)
+{
+	if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
+		return;
+
+	ucom_unit_free(ssc->sc_unit);
+
+	ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
+}
+
+/*------------------------------------------------------------------------*
+ *	ucom_unref
+ *
+ * This function will decrement the super UCOM reference count.
+ *
+ * Return values:
+ * 0: UCOM structures are still referenced.
+ * Else: UCOM structures are no longer referenced.
+ *------------------------------------------------------------------------*/
+int
+ucom_unref(struct ucom_super_softc *ssc)
+{
+	int retval;
+
+	mtx_lock(&ucom_mtx);
+	retval = (ssc->sc_refs < 2);
+	ssc->sc_refs--;
+	mtx_unlock(&ucom_mtx);
+
+	if (retval)
+		ucom_free_unit(ssc);
+
+	return (retval);
+}
+
 #if defined(GDB)
 
 #include <gdb/gdb.h>

Modified: trunk/sys/dev/usb/serial/usb_serial.h
===================================================================
--- trunk/sys/dev/usb/serial/usb_serial.h	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/usb_serial.h	2013-12-28 15:28:46 UTC (rev 6568)
@@ -78,6 +78,7 @@
 #define	UCOM_MINVER	1
 #define	UCOM_PREFVER	UCOM_MODVER
 #define	UCOM_MAXVER	1
+#define	UCOM_JITTERBUF_SIZE	128	/* bytes */
 
 struct usb_device;
 struct ucom_softc;
@@ -107,6 +108,7 @@
 	void    (*ucom_stop_write) (struct ucom_softc *);
 	void    (*ucom_tty_name) (struct ucom_softc *, char *pbuf, uint16_t buflen, uint16_t unit, uint16_t subunit);
 	void    (*ucom_poll) (struct ucom_softc *);
+	void	(*ucom_free) (struct ucom_softc *);
 };
 
 /* Line status register */
@@ -135,6 +137,8 @@
 	struct usb_process sc_tq;
 	int sc_unit;
 	int sc_subunits;
+	int sc_refs;
+	int sc_flag;	/* see UCOM_FLAG_XXX */
 	struct sysctl_oid *sc_sysctl_ttyname;
 	struct sysctl_oid *sc_sysctl_ttyports;
 	char sc_ttyname[16];
@@ -158,7 +162,6 @@
 	struct ucom_cfg_task	sc_line_state_task[2];
 	struct ucom_cfg_task	sc_status_task[2];
 	struct ucom_param_task	sc_param_task[2];
-	struct cv sc_cv;
 	/* Used to set "UCOM_FLAG_GP_DATA" flag: */
 	struct usb_proc_msg	*sc_last_start_xfer;
 	const struct ucom_callback *sc_callback;
@@ -167,6 +170,8 @@
 	struct mtx *sc_mtx;
 	void   *sc_parent;
 	int sc_subunit;
+	uint16_t sc_jitterbuf_in;
+	uint16_t sc_jitterbuf_out;
 	uint16_t sc_portno;
 	uint16_t sc_flag;
 #define	UCOM_FLAG_RTS_IFLOW	0x01	/* use RTS input flow control */
@@ -176,10 +181,12 @@
 #define	UCOM_FLAG_LL_READY	0x20	/* set if low layer is ready */
 #define	UCOM_FLAG_HL_READY	0x40	/* set if high layer is ready */
 #define	UCOM_FLAG_CONSOLE	0x80	/* set if device is a console */
+#define	UCOM_FLAG_WAIT_REFS   0x0100	/* set if we must wait for refs */
+#define	UCOM_FLAG_FREE_UNIT   0x0200	/* set if we must free the unit */
+#define	UCOM_FLAG_INWAKEUP    0x0400	/* set if we are in the tsw_inwakeup callback */
 	uint8_t	sc_lsr;
 	uint8_t	sc_msr;
 	uint8_t	sc_mcr;
-	uint8_t	sc_ttyfreed;		/* set when TTY has been freed */
 	/* programmed line state bits */
 	uint8_t sc_pls_set;		/* set bits */
 	uint8_t sc_pls_clr;		/* cleared bits */
@@ -188,8 +195,15 @@
 #define	UCOM_LS_RTS	0x02
 #define	UCOM_LS_BREAK	0x04
 #define	UCOM_LS_RING	0x08
+	uint8_t sc_jitterbuf[UCOM_JITTERBUF_SIZE];
 };
 
+#define	UCOM_MTX_ASSERT(sc, what) mtx_assert((sc)->sc_mtx, what)
+#define	UCOM_MTX_LOCK(sc) mtx_lock((sc)->sc_mtx)
+#define	UCOM_MTX_UNLOCK(sc) mtx_unlock((sc)->sc_mtx)
+#define	UCOM_UNLOAD_DRAIN(x) \
+SYSUNINIT(var, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_drain_all, 0)
+
 #define	ucom_cfg_do_request(udev,com,req,ptr,flags,timo) \
     usbd_do_request_proc(udev,&(com)->sc_super->sc_tq,req,ptr,flags,NULL,timo)
 
@@ -204,4 +218,8 @@
 void	ucom_put_data(struct ucom_softc *, struct usb_page_cache *,
 	    uint32_t, uint32_t);
 uint8_t	ucom_cfg_is_gone(struct ucom_softc *);
+void	ucom_drain(struct ucom_super_softc *);
+void	ucom_drain_all(void *);
+void	ucom_ref(struct ucom_super_softc *);
+int	ucom_unref(struct ucom_super_softc *);
 #endif					/* _USB_SERIAL_H_ */

Modified: trunk/sys/dev/usb/serial/uslcom.c
===================================================================
--- trunk/sys/dev/usb/serial/uslcom.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uslcom.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -19,6 +19,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+/*
+ * Driver for Silicon Laboratories CP2101/CP2102/CP2103/CP2104/CP2105
+ * USB-Serial adapters.  Based on datasheet AN571, publicly available from
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN571.pdf
+ */
+
 #include <sys/stdint.h>
 #include <sys/stddef.h>
 #include <sys/param.h>
@@ -53,7 +59,7 @@
 #ifdef USB_DEBUG
 static int uslcom_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom");
 SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW,
     &uslcom_debug, 0, "Debug level");
 #endif
@@ -60,58 +66,55 @@
 
 #define	USLCOM_BULK_BUF_SIZE		1024
 #define	USLCOM_CONFIG_INDEX	0
-#define	USLCOM_IFACE_INDEX	0
 
-#define	USLCOM_SET_DATA_BITS(x)	((x) << 8)
-
 /* Request types */
 #define	USLCOM_WRITE		0x41
 #define	USLCOM_READ		0xc1
 
 /* Request codes */
-#define	USLCOM_UART		0x00
-#define	USLCOM_BAUD_RATE	0x01	
-#define	USLCOM_DATA		0x03
-#define	USLCOM_BREAK		0x05
-#define	USLCOM_CTRL		0x07
-#define	USLCOM_RCTRL            0x08
-#define	USLCOM_SET_FLOWCTRL     0x13
+#define	USLCOM_IFC_ENABLE	0x00
+#define	USLCOM_SET_BAUDDIV	0x01	
+#define	USLCOM_SET_LINE_CTL	0x03
+#define	USLCOM_SET_BREAK	0x05
+#define	USLCOM_SET_MHS		0x07
+#define	USLCOM_GET_MDMSTS	0x08
+#define	USLCOM_SET_FLOW		0x13
+#define	USLCOM_SET_BAUDRATE	0x1e	
 #define	USLCOM_VENDOR_SPECIFIC	0xff
 
-/* USLCOM_UART values */
-#define	USLCOM_UART_DISABLE	0x00
-#define	USLCOM_UART_ENABLE	0x01
+/* USLCOM_IFC_ENABLE values */
+#define	USLCOM_IFC_ENABLE_DIS	0x00
+#define	USLCOM_IFC_ENABLE_EN	0x01
 
-/* USLCOM_CTRL/USLCOM_RCTRL values */
-#define	USLCOM_CTRL_DTR_ON	0x0001	
-#define	USLCOM_CTRL_DTR_SET	0x0100
-#define	USLCOM_CTRL_RTS_ON	0x0002
-#define	USLCOM_CTRL_RTS_SET	0x0200
-#define	USLCOM_CTRL_CTS		0x0010
-#define	USLCOM_CTRL_DSR		0x0020
-#define	USLCOM_CTRL_RI          0x0040
-#define	USLCOM_CTRL_DCD		0x0080
+/* USLCOM_SET_MHS/USLCOM_GET_MDMSTS values */
+#define	USLCOM_MHS_DTR_ON	0x0001	
+#define	USLCOM_MHS_DTR_SET	0x0100
+#define	USLCOM_MHS_RTS_ON	0x0002
+#define	USLCOM_MHS_RTS_SET	0x0200
+#define	USLCOM_MHS_CTS		0x0010
+#define	USLCOM_MHS_DSR		0x0020
+#define	USLCOM_MHS_RI		0x0040
+#define	USLCOM_MHS_DCD		0x0080
 
-/* USLCOM_BAUD_RATE values */
-#define	USLCOM_BAUD_REF		0x384000
+/* USLCOM_SET_BAUDDIV values */
+#define	USLCOM_BAUDDIV_REF	3686400 /* 3.6864 MHz */
 
-/* USLCOM_DATA values */
+/* USLCOM_SET_LINE_CTL values */
 #define	USLCOM_STOP_BITS_1	0x00
 #define	USLCOM_STOP_BITS_2	0x02
 #define	USLCOM_PARITY_NONE	0x00
 #define	USLCOM_PARITY_ODD	0x10
 #define	USLCOM_PARITY_EVEN	0x20
+#define	USLCOM_SET_DATA_BITS(x)	((x) << 8)
 
-#define	USLCOM_PORT_NO		0x0000
+/* USLCOM_SET_BREAK values */
+#define	USLCOM_SET_BREAK_OFF	0x00
+#define	USLCOM_SET_BREAK_ON	0x01
 
-/* USLCOM_BREAK values */
-#define	USLCOM_BREAK_OFF	0x00
-#define	USLCOM_BREAK_ON		0x01
-
-/* USLCOM_SET_FLOWCTRL values - 1st word */
+/* USLCOM_SET_FLOW values - 1st word */
 #define	USLCOM_FLOW_DTR_ON      0x00000001 /* DTR static active */
 #define	USLCOM_FLOW_CTS_HS      0x00000008 /* CTS handshake */
-/* USLCOM_SET_FLOWCTRL values - 2nd word */
+/* USLCOM_SET_FLOW values - 2nd word */
 #define	USLCOM_FLOW_RTS_ON      0x00000040 /* RTS static active */
 #define	USLCOM_FLOW_RTS_HS      0x00000080 /* RTS handshake */
 
@@ -137,16 +140,19 @@
 
 	uint8_t		 sc_msr;
 	uint8_t		 sc_lsr;
+	uint8_t		 sc_iface_no;
 };
 
 static device_probe_t uslcom_probe;
 static device_attach_t uslcom_attach;
 static device_detach_t uslcom_detach;
+static void uslcom_free_softc(struct uslcom_softc *);
 
 static usb_callback_t uslcom_write_callback;
 static usb_callback_t uslcom_read_callback;
 static usb_callback_t uslcom_control_callback;
 
+static void	uslcom_free(struct ucom_softc *);
 static void uslcom_open(struct ucom_softc *);
 static void uslcom_close(struct ucom_softc *);
 static void uslcom_set_dtr(struct ucom_softc *, uint8_t);
@@ -208,12 +214,19 @@
 	.ucom_start_write = &uslcom_start_write,
 	.ucom_stop_write = &uslcom_stop_write,
 	.ucom_poll = &uslcom_poll,
+	.ucom_free = &uslcom_free,
 };
 
 static const STRUCT_USB_HOST_ID uslcom_devs[] = {
 #define	USLCOM_DEV(v,p)  { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
     USLCOM_DEV(BALTECH, CARDREADER),
+    USLCOM_DEV(CLIPSAL, 5000CT2),
+    USLCOM_DEV(CLIPSAL, 5500PACA),
     USLCOM_DEV(CLIPSAL, 5500PCU),
+    USLCOM_DEV(CLIPSAL, 560884),
+    USLCOM_DEV(CLIPSAL, 5800PC),
+    USLCOM_DEV(CLIPSAL, C5000CT2),
+    USLCOM_DEV(CLIPSAL, L51xx),
     USLCOM_DEV(DATAAPEX, MULTICOM),
     USLCOM_DEV(DELL, DW700),
     USLCOM_DEV(DIGIANSWER, ZIGBEE802154),
@@ -221,17 +234,27 @@
     USLCOM_DEV(DYNASTREAM, ANTDEVBOARD2),
     USLCOM_DEV(DYNASTREAM, ANT2USB),
     USLCOM_DEV(ELV, USBI2C),
+    USLCOM_DEV(FESTO, CMSP),
+    USLCOM_DEV(FESTO, CPX_USB),
     USLCOM_DEV(FOXCONN, PIRELLI_DP_L10),
     USLCOM_DEV(FOXCONN, TCOM_TC_300),
     USLCOM_DEV(GEMALTO, PROXPU),
     USLCOM_DEV(JABLOTRON, PC60B),
+    USLCOM_DEV(KAMSTRUP, OPTICALEYE),
+    USLCOM_DEV(KAMSTRUP, MBUS_250D),
+    USLCOM_DEV(LINKINSTRUMENTS, MSO19),
+    USLCOM_DEV(LINKINSTRUMENTS, MSO28),
+    USLCOM_DEV(LINKINSTRUMENTS, MSO28_2),
     USLCOM_DEV(MEI, CASHFLOW_SC),
     USLCOM_DEV(MEI, S2000),
-    USLCOM_DEV(JABLOTRON, PC60B),
     USLCOM_DEV(OWEN, AC4),
     USLCOM_DEV(PHILIPS, ACE1001),
     USLCOM_DEV(PLX, CA42),
     USLCOM_DEV(RENESAS, RX610),
+    USLCOM_DEV(SILABS, AC_SERV_CAN),
+    USLCOM_DEV(SILABS, AC_SERV_CIS),
+    USLCOM_DEV(SILABS, AC_SERV_IBUS),
+    USLCOM_DEV(SILABS, AC_SERV_OBD),
     USLCOM_DEV(SILABS, AEROCOMM),
     USLCOM_DEV(SILABS, AMBER_AMB2560),
     USLCOM_DEV(SILABS, ARGUSISP),
@@ -247,16 +270,21 @@
     USLCOM_DEV(SILABS, C2_EDGE_MODEM),
     USLCOM_DEV(SILABS, CP2102),
     USLCOM_DEV(SILABS, CP210X_2),
+    USLCOM_DEV(SILABS, CP210X_3),
+    USLCOM_DEV(SILABS, CP210X_4),
     USLCOM_DEV(SILABS, CRUMB128),
     USLCOM_DEV(SILABS, CYGNAL),
     USLCOM_DEV(SILABS, CYGNAL_DEBUG),
     USLCOM_DEV(SILABS, CYGNAL_GPS),
     USLCOM_DEV(SILABS, DEGREE),
+    USLCOM_DEV(SILABS, DEKTEK_DTAPLUS),
     USLCOM_DEV(SILABS, EMS_C1007),
+    USLCOM_DEV(SILABS, HAMLINKUSB),
     USLCOM_DEV(SILABS, HELICOM),
     USLCOM_DEV(SILABS, IMS_USB_RS422),
     USLCOM_DEV(SILABS, INFINITY_MIC),
     USLCOM_DEV(SILABS, INSYS_MODEM),
+    USLCOM_DEV(SILABS, IRZ_SG10),
     USLCOM_DEV(SILABS, KYOCERA_GPS),
     USLCOM_DEV(SILABS, LIPOWSKY_HARP),
     USLCOM_DEV(SILABS, LIPOWSKY_JTAG),
@@ -264,12 +292,14 @@
     USLCOM_DEV(SILABS, MC35PU),
     USLCOM_DEV(SILABS, MJS_TOSLINK),
     USLCOM_DEV(SILABS, MSD_DASHHAWK),
+    USLCOM_DEV(SILABS, MULTIPLEX_RC),
+    USLCOM_DEV(SILABS, OPTRIS_MSPRO),
     USLCOM_DEV(SILABS, POLOLU),
     USLCOM_DEV(SILABS, PROCYON_AVS),
     USLCOM_DEV(SILABS, SB_PARAMOUNT_ME),
     USLCOM_DEV(SILABS, SUUNTO),
     USLCOM_DEV(SILABS, TAMSMASTER),
-    USLCOM_DEV(SILABS, TELEGESYS_ETRX2),
+    USLCOM_DEV(SILABS, TELEGESIS_ETRX2),
     USLCOM_DEV(SILABS, TRACIENT),
     USLCOM_DEV(SILABS, TRAQMATE),
     USLCOM_DEV(SILABS, USBCOUNT50),
@@ -301,7 +331,7 @@
 	DEVMETHOD(device_probe, uslcom_probe),
 	DEVMETHOD(device_attach, uslcom_attach),
 	DEVMETHOD(device_detach, uslcom_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t uslcom_devclass;
@@ -343,9 +373,6 @@
 	if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) {
 		return (ENXIO);
 	}
-	if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) {
-		return (ENXIO);
-	}
 	return (usbd_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa));
 }
 
@@ -360,9 +387,12 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 	usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
 
 	sc->sc_udev = uaa->device;
+	/* use the interface number from the USB interface descriptor */
+	sc->sc_iface_no = uaa->info.bIfaceNum;
 
 	error = usbd_transfer_setup(uaa->device,
 	    &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config,
@@ -403,12 +433,32 @@
 	usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER);
 
 	usb_callout_drain(&sc->sc_watchdog);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uslcom_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uslcom);
+
 static void
+uslcom_free_softc(struct uslcom_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uslcom_free(struct ucom_softc *ucom)
+{
+	uslcom_free_softc(ucom->sc_parent);
+}
+
+static void
 uslcom_open(struct ucom_softc *ucom)
 {
 	struct uslcom_softc *sc = ucom->sc_parent;
@@ -415,9 +465,9 @@
 	struct usb_device_request req;
 
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_UART;
-	USETW(req.wValue, USLCOM_UART_ENABLE);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	req.bRequest = USLCOM_IFC_ENABLE;
+	USETW(req.wValue, USLCOM_IFC_ENABLE_EN);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, 0);
 
         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -439,9 +489,9 @@
 	usb_callout_stop(&sc->sc_watchdog);
 
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_UART;
-	USETW(req.wValue, USLCOM_UART_DISABLE);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	req.bRequest = USLCOM_IFC_ENABLE;
+	USETW(req.wValue, USLCOM_IFC_ENABLE_DIS);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, 0);
 
 	if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -459,13 +509,13 @@
 
         DPRINTF("onoff = %d\n", onoff);
 
-	ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
-	ctl |= USLCOM_CTRL_DTR_SET;
+	ctl = onoff ? USLCOM_MHS_DTR_ON : 0;
+	ctl |= USLCOM_MHS_DTR_SET;
 
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_CTRL;
+	req.bRequest = USLCOM_SET_MHS;
 	USETW(req.wValue, ctl);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, 0);
 
         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -483,13 +533,13 @@
 
         DPRINTF("onoff = %d\n", onoff);
 
-	ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
-	ctl |= USLCOM_CTRL_RTS_SET;
+	ctl = onoff ? USLCOM_MHS_RTS_ON : 0;
+	ctl |= USLCOM_MHS_RTS_SET;
 
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_CTRL;
+	req.bRequest = USLCOM_SET_MHS;
 	USETW(req.wValue, ctl);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, 0);
 
         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -511,19 +561,20 @@
 {
 	struct uslcom_softc *sc = ucom->sc_parent;
 	struct usb_device_request req;
-	uint32_t flowctrl[4];
+	uint32_t baudrate, flowctrl[4];
 	uint16_t data;
 
 	DPRINTF("\n");
 
+	baudrate = t->c_ospeed;
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_BAUD_RATE;
-	USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed);
-	USETW(req.wIndex, USLCOM_PORT_NO);
-	USETW(req.wLength, 0);
+	req.bRequest = USLCOM_SET_BAUDRATE;
+	USETW(req.wValue, 0);
+	USETW(req.wIndex, sc->sc_iface_no);
+	USETW(req.wLength, sizeof(baudrate));
 
-        if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
-	    &req, NULL, 0, 1000)) {
+	if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
+	    &req, &baudrate, 0, 1000)) {
 		DPRINTF("Set baudrate failed (ignored)\n");
 	}
 
@@ -554,9 +605,9 @@
 	}
 
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_DATA;
+	req.bRequest = USLCOM_SET_LINE_CTL;
 	USETW(req.wValue, data);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, 0);
 
         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -567,18 +618,16 @@
 	if (t->c_cflag & CRTSCTS) {
 		flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS);
 		flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS);
-		flowctrl[2] = 0;
-		flowctrl[3] = 0;
 	} else {
 		flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON);
 		flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON);
-		flowctrl[2] = 0;
-		flowctrl[3] = 0;
 	}
+	flowctrl[2] = 0;
+	flowctrl[3] = 0;
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_SET_FLOWCTRL;
+	req.bRequest = USLCOM_SET_FLOW;
 	USETW(req.wValue, 0);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, sizeof(flowctrl));
 
 	if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -603,12 +652,12 @@
 {
         struct uslcom_softc *sc = ucom->sc_parent;
 	struct usb_device_request req;
-	uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;
+	uint16_t brk = onoff ? USLCOM_SET_BREAK_ON : USLCOM_SET_BREAK_OFF;
 
 	req.bmRequestType = USLCOM_WRITE;
-	req.bRequest = USLCOM_BREAK;
+	req.bRequest = USLCOM_SET_BREAK;
 	USETW(req.wValue, brk);
-	USETW(req.wIndex, USLCOM_PORT_NO);
+	USETW(req.wIndex, sc->sc_iface_no);
 	USETW(req.wLength, 0);
 
         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -741,13 +790,13 @@
 	case USB_ST_TRANSFERRED:
 		pc = usbd_xfer_get_frame(xfer, 1);
 		usbd_copy_out(pc, 0, &buf, sizeof(buf));
-		if (buf & USLCOM_CTRL_CTS)
+		if (buf & USLCOM_MHS_CTS)
 			msr |= SER_CTS;
-		if (buf & USLCOM_CTRL_DSR)
+		if (buf & USLCOM_MHS_DSR)
 			msr |= SER_DSR;
-		if (buf & USLCOM_CTRL_RI)
+		if (buf & USLCOM_MHS_RI)
 			msr |= SER_RI;
-		if (buf & USLCOM_CTRL_DCD)
+		if (buf & USLCOM_MHS_DCD)
 			msr |= SER_DCD;
 
 		if (msr != sc->sc_msr) {
@@ -760,9 +809,9 @@
 
 	case USB_ST_SETUP:
 		req.bmRequestType = USLCOM_READ;
-		req.bRequest = USLCOM_RCTRL;
+		req.bRequest = USLCOM_GET_MDMSTS;
 		USETW(req.wValue, 0);
-		USETW(req.wIndex, USLCOM_PORT_NO);
+		USETW(req.wIndex, sc->sc_iface_no);
 		USETW(req.wLength, sizeof(buf));
                
 		usbd_xfer_set_frames(xfer, 2);

Modified: trunk/sys/dev/usb/serial/uvisor.c
===================================================================
--- trunk/sys/dev/usb/serial/uvisor.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uvisor.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -80,7 +80,7 @@
 #ifdef USB_DEBUG
 static int uvisor_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uvisor, CTLFLAG_RW, 0, "USB uvisor");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uvisor, CTLFLAG_RW, 0, "USB uvisor");
 SYSCTL_INT(_hw_usb_uvisor, OID_AUTO, debug, CTLFLAG_RW,
     &uvisor_debug, 0, "Debug level");
 #endif
@@ -189,6 +189,7 @@
 static device_probe_t uvisor_probe;
 static device_attach_t uvisor_attach;
 static device_detach_t uvisor_detach;
+static void uvisor_free_softc(struct uvisor_softc *);
 
 static usb_callback_t uvisor_write_callback;
 static usb_callback_t uvisor_read_callback;
@@ -195,6 +196,7 @@
 
 static usb_error_t uvisor_init(struct uvisor_softc *, struct usb_device *,
 		    struct usb_config *);
+static void	uvisor_free(struct ucom_softc *);
 static void	uvisor_cfg_open(struct ucom_softc *);
 static void	uvisor_cfg_close(struct ucom_softc *);
 static void	uvisor_start_read(struct ucom_softc *);
@@ -231,6 +233,7 @@
 	.ucom_stop_read = &uvisor_stop_read,
 	.ucom_start_write = &uvisor_start_write,
 	.ucom_stop_write = &uvisor_stop_write,
+	.ucom_free = &uvisor_free,
 };
 
 static device_method_t uvisor_methods[] = {
@@ -237,7 +240,7 @@
 	DEVMETHOD(device_probe, uvisor_probe),
 	DEVMETHOD(device_attach, uvisor_attach),
 	DEVMETHOD(device_detach, uvisor_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t uvisor_devclass;
@@ -317,6 +320,7 @@
 	device_set_usb_desc(dev);
 
 	mtx_init(&sc->sc_mtx, "uvisor", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_udev = uaa->device;
 
@@ -365,11 +369,31 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UVISOR_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uvisor_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uvisor);
+
+static void
+uvisor_free_softc(struct uvisor_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uvisor_free(struct ucom_softc *ucom)
+{
+	uvisor_free_softc(ucom->sc_parent);
+}
+
 static usb_error_t
 uvisor_init(struct uvisor_softc *sc, struct usb_device *udev, struct usb_config *config)
 {

Modified: trunk/sys/dev/usb/serial/uvscom.c
===================================================================
--- trunk/sys/dev/usb/serial/uvscom.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/serial/uvscom.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -70,7 +70,7 @@
 #ifdef USB_DEBUG
 static int uvscom_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
 SYSCTL_INT(_hw_usb_uvscom, OID_AUTO, debug, CTLFLAG_RW,
     &uvscom_debug, 0, "Debug level");
 #endif
@@ -163,11 +163,13 @@
 static device_probe_t uvscom_probe;
 static device_attach_t uvscom_attach;
 static device_detach_t uvscom_detach;
+static void uvscom_free_softc(struct uvscom_softc *);
 
 static usb_callback_t uvscom_write_callback;
 static usb_callback_t uvscom_read_callback;
 static usb_callback_t uvscom_intr_callback;
 
+static void	uvscom_free(struct ucom_softc *);
 static void	uvscom_cfg_set_dtr(struct ucom_softc *, uint8_t);
 static void	uvscom_cfg_set_rts(struct ucom_softc *, uint8_t);
 static void	uvscom_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -231,6 +233,7 @@
 	.ucom_start_write = &uvscom_start_write,
 	.ucom_stop_write = &uvscom_stop_write,
 	.ucom_poll = &uvscom_poll,
+	.ucom_free = &uvscom_free,
 };
 
 static const STRUCT_USB_HOST_ID uvscom_devs[] = {
@@ -250,7 +253,7 @@
 	DEVMETHOD(device_probe, uvscom_probe),
 	DEVMETHOD(device_attach, uvscom_attach),
 	DEVMETHOD(device_detach, uvscom_detach),
-	{0, 0}
+	DEVMETHOD_END
 };
 
 static devclass_t uvscom_devclass;
@@ -292,6 +295,7 @@
 
 	device_set_usb_desc(dev);
 	mtx_init(&sc->sc_mtx, "uvscom", NULL, MTX_DEF);
+	ucom_ref(&sc->sc_super_ucom);
 
 	sc->sc_udev = uaa->device;
 
@@ -348,12 +352,32 @@
 
 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
 	usbd_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER);
-	mtx_destroy(&sc->sc_mtx);
 
+	device_claim_softc(dev);
+
+	uvscom_free_softc(sc);
+
 	return (0);
 }
 
+UCOM_UNLOAD_DRAIN(uvscom);
+
 static void
+uvscom_free_softc(struct uvscom_softc *sc)
+{
+	if (ucom_unref(&sc->sc_super_ucom)) {
+		mtx_destroy(&sc->sc_mtx);
+		device_free_softc(sc);
+	}
+}
+
+static void
+uvscom_free(struct ucom_softc *ucom)
+{
+	uvscom_free_softc(ucom->sc_parent);
+}
+
+static void
 uvscom_write_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct uvscom_softc *sc = usbd_xfer_softc(xfer);

Modified: trunk/sys/dev/usb/storage/umass.c
===================================================================
--- trunk/sys/dev/usb/storage/umass.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/storage/umass.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -137,14 +137,6 @@
 
 #include <cam/cam_periph.h>
 
-#define UMASS_EXT_BUFFER
-#ifdef UMASS_EXT_BUFFER
-/* this enables loading of virtual buffers into DMA */
-#define	UMASS_USB_FLAGS .ext_buffer=1,
-#else
-#define	UMASS_USB_FLAGS
-#endif
-
 #ifdef USB_DEBUG
 #define	DIF(m, x)				\
   do {						\
@@ -171,20 +163,21 @@
 #define	UDMASS_CBI	0x00400000	/* CBI transfers */
 #define	UDMASS_WIRE	(UDMASS_BBB|UDMASS_CBI)
 #define	UDMASS_ALL	0xffff0000	/* all of the above */
-static int umass_debug = 0;
+static int umass_debug;
+static int umass_throttle;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass");
-SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW,
+static SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass");
+SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
     &umass_debug, 0, "umass debug level");
-
 TUNABLE_INT("hw.usb.umass.debug", &umass_debug);
+SYSCTL_INT(_hw_usb_umass, OID_AUTO, throttle, CTLFLAG_RW | CTLFLAG_TUN,
+    &umass_throttle, 0, "Forced delay between commands in milliseconds");
+TUNABLE_INT("hw.usb.umass.throttle", &umass_throttle);
 #else
 #define	DIF(...) do { } while (0)
 #define	DPRINTF(...) do { } while (0)
 #endif
 
-#define	UMASS_GONE ((struct umass_softc *)1)
-
 #define	UMASS_BULK_SIZE (1 << 17)
 #define	UMASS_CBI_DIAGNOSTIC_CMDLEN 12	/* bytes */
 #define	UMASS_MAX_CMDLEN MAX(12, CAM_MAX_CDBLEN)	/* bytes */
@@ -372,6 +365,8 @@
 	 * result.
 	 */
 #define	NO_SYNCHRONIZE_CACHE	0x4000
+	/* Device does not support 'PREVENT/ALLOW MEDIUM REMOVAL'. */
+#define	NO_PREVENT_ALLOW	0x8000
 
 struct umass_softc {
 
@@ -542,7 +537,7 @@
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_IN,
 		.bufsize = UMASS_BULK_SIZE,
-		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
+		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
 		.callback = &umass_t_bbb_data_read_callback,
 		.timeout = 0,	/* overwritten later */
 	},
@@ -561,7 +556,7 @@
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_OUT,
 		.bufsize = UMASS_BULK_SIZE,
-		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
+		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
 		.callback = &umass_t_bbb_data_write_callback,
 		.timeout = 0,	/* overwritten later */
 	},
@@ -634,7 +629,7 @@
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_IN,
 		.bufsize = UMASS_BULK_SIZE,
-		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
+		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
 		.callback = &umass_t_cbi_data_read_callback,
 		.timeout = 0,	/* overwritten later */
 	},
@@ -653,7 +648,7 @@
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_OUT,
 		.bufsize = UMASS_BULK_SIZE,
-		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
+		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
 		.callback = &umass_t_cbi_data_write_callback,
 		.timeout = 0,	/* overwritten later */
 	},
@@ -842,6 +837,8 @@
 		quirks |= NO_INQUIRY;
 	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY_EVPD))
 		quirks |= NO_INQUIRY_EVPD;
+	if (usb_test_quirk(uaa, UQ_MSC_NO_PREVENT_ALLOW))
+		quirks |= NO_PREVENT_ALLOW;
 	if (usb_test_quirk(uaa, UQ_MSC_NO_SYNC_CACHE))
 		quirks |= NO_SYNCHRONIZE_CACHE;
 	if (usb_test_quirk(uaa, UQ_MSC_SHUTTLE_INIT))
@@ -888,7 +885,7 @@
 	struct usb_attach_arg *uaa = device_get_ivars(dev);
 	struct umass_probe_proto temp = umass_probe_proto(dev, uaa);
 	struct usb_interface_descriptor *id;
-	int32_t err;
+	int err;
 
 	/*
 	 * NOTE: the softc struct is cleared in device_set_driver.
@@ -1001,6 +998,24 @@
 		    "transfers, %s\n", usbd_errstr(err));
 		goto detach;
 	}
+#ifdef USB_DEBUG
+	if (umass_throttle > 0) {
+		uint8_t x;
+		int iv;
+
+		iv = umass_throttle;
+
+		if (iv < 1)
+			iv = 1;
+		else if (iv > 8000)
+			iv = 8000;
+
+		for (x = 0; x != UMASS_T_MAX; x++) {
+			if (sc->sc_xfer[x] != NULL)
+				usbd_xfer_set_interval(sc->sc_xfer[x], iv);
+		}
+	}
+#endif
 	sc->sc_transform =
 	    (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform :
 	    (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform :
@@ -1053,14 +1068,16 @@
 
 	usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX);
 
-#if (__FreeBSD_version >= 700037)
 	mtx_lock(&sc->sc_mtx);
-#endif
+
+	/* cancel any leftover CCB's */
+
+	umass_cancel_ccb(sc);
+
 	umass_cam_detach_sim(sc);
 
-#if (__FreeBSD_version >= 700037)
 	mtx_unlock(&sc->sc_mtx);
-#endif
+
 	mtx_destroy(&sc->sc_mtx);
 
 	return (0);			/* success */
@@ -1201,7 +1218,6 @@
 	default:			/* Error */
 		umass_tr_error(xfer, error);
 		return;
-
 	}
 }
 
@@ -1240,7 +1256,6 @@
 	default:			/* Error */
 		umass_tr_error(xfer, error);
 		return;
-
 	}
 }
 
@@ -1326,7 +1341,6 @@
 	default:			/* Error */
 		umass_tr_error(xfer, error);
 		return;
-
 	}
 }
 
@@ -1335,9 +1349,6 @@
 {
 	struct umass_softc *sc = usbd_xfer_softc(xfer);
 	uint32_t max_bulk = usbd_xfer_max_len(xfer);
-#ifndef UMASS_EXT_BUFFER
-	struct usb_page_cache *pc;
-#endif
 	int actlen, sumlen;
 
 	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
@@ -1344,10 +1355,6 @@
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-#ifndef UMASS_EXT_BUFFER
-		pc = usbd_xfer_get_frame(xfer, 0);
-		usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen);
-#endif
 		sc->sc_transfer.data_rem -= actlen;
 		sc->sc_transfer.data_ptr += actlen;
 		sc->sc_transfer.actlen += actlen;
@@ -1369,12 +1376,9 @@
 		}
 		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
 
-#ifdef UMASS_EXT_BUFFER
 		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
 		    max_bulk);
-#else
-		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
-#endif
+
 		usbd_transfer_submit(xfer);
 		return;
 
@@ -1385,7 +1389,6 @@
 			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
 		}
 		return;
-
 	}
 }
 
@@ -1401,9 +1404,6 @@
 {
 	struct umass_softc *sc = usbd_xfer_softc(xfer);
 	uint32_t max_bulk = usbd_xfer_max_len(xfer);
-#ifndef UMASS_EXT_BUFFER
-	struct usb_page_cache *pc;
-#endif
 	int actlen, sumlen;
 
 	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
@@ -1431,14 +1431,8 @@
 		}
 		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
 
-#ifdef UMASS_EXT_BUFFER
 		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
 		    max_bulk);
-#else
-		pc = usbd_xfer_get_frame(xfer, 0);
-		usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk);
-		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
-#endif
 
 		usbd_transfer_submit(xfer);
 		return;
@@ -1450,7 +1444,6 @@
 			umass_transfer_start(sc, UMASS_T_BBB_DATA_WR_CS);
 		}
 		return;
-
 	}
 }
 
@@ -1576,7 +1569,6 @@
 			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
 		}
 		return;
-
 	}
 }
 
@@ -1607,8 +1599,7 @@
 	if (sc->sc_xfer[sc->sc_last_xfer_index]) {
 		usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]);
 	} else {
-		ccb->ccb_h.status = CAM_TID_INVALID;
-		xpt_done(ccb);
+		umass_cancel_ccb(sc);
 	}
 }
 
@@ -1728,7 +1719,6 @@
 		else
 			umass_transfer_start(sc, UMASS_T_CBI_RESET2);
 		break;
-
 	}
 }
 
@@ -1783,7 +1773,6 @@
 	default:			/* Error */
 		umass_tr_error(xfer, error);
 		break;
-
 	}
 }
 
@@ -1873,9 +1862,6 @@
 {
 	struct umass_softc *sc = usbd_xfer_softc(xfer);
 	uint32_t max_bulk = usbd_xfer_max_len(xfer);
-#ifndef UMASS_EXT_BUFFER
-	struct usb_page_cache *pc;
-#endif
 	int actlen, sumlen;
 
 	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
@@ -1882,10 +1868,6 @@
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-#ifndef UMASS_EXT_BUFFER
-		pc = usbd_xfer_get_frame(xfer, 0);
-		usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen);
-#endif
 		sc->sc_transfer.data_rem -= actlen;
 		sc->sc_transfer.data_ptr += actlen;
 		sc->sc_transfer.actlen += actlen;
@@ -1907,12 +1889,9 @@
 		}
 		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
 
-#ifdef UMASS_EXT_BUFFER
 		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
 		    max_bulk);
-#else
-		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
-#endif
+
 		usbd_transfer_submit(xfer);
 		break;
 
@@ -1924,7 +1903,6 @@
 			umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS);
 		}
 		break;
-
 	}
 }
 
@@ -1940,9 +1918,6 @@
 {
 	struct umass_softc *sc = usbd_xfer_softc(xfer);
 	uint32_t max_bulk = usbd_xfer_max_len(xfer);
-#ifndef UMASS_EXT_BUFFER
-	struct usb_page_cache *pc;
-#endif
 	int actlen, sumlen;
 
 	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
@@ -1970,14 +1945,8 @@
 		}
 		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
 
-#ifdef UMASS_EXT_BUFFER
 		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
 		    max_bulk);
-#else
-		pc = usbd_xfer_get_frame(xfer, 0);
-		usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk);
-		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
-#endif
 
 		usbd_transfer_submit(xfer);
 		break;
@@ -1990,7 +1959,6 @@
 			umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS);
 		}
 		break;
-
 	}
 }
 
@@ -2092,7 +2060,6 @@
 		    usbd_errstr(error));
 		umass_tr_error(xfer, error);
 		break;
-
 	}
 }
 
@@ -2121,9 +2088,7 @@
 	    DEVNAME_SIM,
 	    sc /* priv */ ,
 	    sc->sc_unit /* unit number */ ,
-#if (__FreeBSD_version >= 700037)
 	    &sc->sc_mtx /* mutex */ ,
-#endif
 	    1 /* maximum device openings */ ,
 	    0 /* maximum tagged device openings */ ,
 	    devq);
@@ -2133,27 +2098,15 @@
 		return (ENOMEM);
 	}
 
-#if (__FreeBSD_version >= 700037)
 	mtx_lock(&sc->sc_mtx);
-#endif
 
-#if (__FreeBSD_version >= 700048)
-	if (xpt_bus_register(sc->sc_sim, sc->sc_dev, sc->sc_unit) != CAM_SUCCESS) {
+	if (xpt_bus_register(sc->sc_sim, sc->sc_dev,
+	    sc->sc_unit) != CAM_SUCCESS) {
 		mtx_unlock(&sc->sc_mtx);
 		return (ENOMEM);
 	}
-#else
-	if (xpt_bus_register(sc->sc_sim, sc->sc_unit) != CAM_SUCCESS) {
-#if (__FreeBSD_version >= 700037)
-		mtx_unlock(&sc->sc_mtx);
-#endif
-		return (ENOMEM);
-	}
-#endif
+	mtx_unlock(&sc->sc_mtx);
 
-#if (__FreeBSD_version >= 700037)
-	mtx_unlock(&sc->sc_mtx);
-#endif
 	return (0);
 }
 
@@ -2179,7 +2132,7 @@
 	if (sc->sc_sim != NULL) {
 		if (xpt_bus_deregister(cam_sim_path(sc->sc_sim))) {
 			/* accessing the softc is not possible after this */
-			sc->sc_sim->softc = UMASS_GONE;
+			sc->sc_sim->softc = NULL;
 			cam_sim_free(sc->sc_sim, /* free_devq */ TRUE);
 		} else {
 			panic("%s: CAM layer is busy\n",
@@ -2198,69 +2151,12 @@
 {
 	struct umass_softc *sc = (struct umass_softc *)sim->softc;
 
-	if (sc == UMASS_GONE ||
-	    (sc != NULL && !usbd_device_attached(sc->sc_udev))) {
+	if (sc == NULL) {
 		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
 		xpt_done(ccb);
 		return;
 	}
-	if (sc) {
-#if (__FreeBSD_version < 700037)
-		mtx_lock(&sc->sc_mtx);
-#endif
-	}
-	/*
-	 * Verify, depending on the operation to perform, that we either got
-	 * a valid sc, because an existing target was referenced, or
-	 * otherwise the SIM is addressed.
-	 *
-	 * This avoids bombing out at a printf and does give the CAM layer some
-	 * sensible feedback on errors.
-	 */
-	switch (ccb->ccb_h.func_code) {
-	case XPT_SCSI_IO:
-	case XPT_RESET_DEV:
-	case XPT_GET_TRAN_SETTINGS:
-	case XPT_SET_TRAN_SETTINGS:
-	case XPT_CALC_GEOMETRY:
-		/* the opcodes requiring a target. These should never occur. */
-		if (sc == NULL) {
-			DPRINTF(sc, UDMASS_GEN, "%s:%d:%d:%d:func_code 0x%04x: "
-			    "Invalid target (target needed)\n",
-			    DEVNAME_SIM, cam_sim_path(sc->sc_sim),
-			    ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
-			    ccb->ccb_h.func_code);
 
-			ccb->ccb_h.status = CAM_TID_INVALID;
-			xpt_done(ccb);
-			goto done;
-		}
-		break;
-	case XPT_PATH_INQ:
-	case XPT_NOOP:
-		/*
-		 * The opcodes sometimes aimed at a target (sc is valid),
-		 * sometimes aimed at the SIM (sc is invalid and target is
-		 * CAM_TARGET_WILDCARD)
-		 */
-		if ((sc == NULL) &&
-		    (ccb->ccb_h.target_id != CAM_TARGET_WILDCARD)) {
-			DPRINTF(sc, UDMASS_SCSI, "%s:%d:%d:%d:func_code 0x%04x: "
-			    "Invalid target (no wildcard)\n",
-			    DEVNAME_SIM, cam_sim_path(sc->sc_sim),
-			    ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
-			    ccb->ccb_h.func_code);
-
-			ccb->ccb_h.status = CAM_TID_INVALID;
-			xpt_done(ccb);
-			goto done;
-		}
-		break;
-	default:
-		/* XXX Hm, we should check the input parameters */
-		break;
-	}
-
 	/* Perform the requested action */
 	switch (ccb->ccb_h.func_code) {
 	case XPT_SCSI_IO:
@@ -2355,8 +2251,11 @@
 							/*ascq*/ 0x00,
 							/*extra args*/ SSD_ELEM_NONE);
 						ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
-						ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
-						    CAM_AUTOSNS_VALID;
+						ccb->ccb_h.status =
+						    CAM_SCSI_STATUS_ERROR |
+						    CAM_AUTOSNS_VALID |
+						    CAM_DEV_QFRZN;
+						xpt_freeze_devq(ccb->ccb_h.path, 1);
 						xpt_done(ccb);
 						goto done;
 					}
@@ -2375,6 +2274,13 @@
 					if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
 						ccb->csio.dxfer_len = SHORT_INQUIRY_LENGTH;
 					}
+				} else if (sc->sc_transfer.cmd_data[0] == PREVENT_ALLOW) {
+					if (sc->sc_quirks & NO_PREVENT_ALLOW) {
+						ccb->csio.scsi_status = SCSI_STATUS_OK;
+						ccb->ccb_h.status = CAM_REQ_CMP;
+						xpt_done(ccb);
+						goto done;
+					}
 				} else if (sc->sc_transfer.cmd_data[0] == SYNCHRONIZE_CACHE) {
 					if (sc->sc_quirks & NO_SYNCHRONIZE_CACHE) {
 						ccb->csio.scsi_status = SCSI_STATUS_OK;
@@ -2411,12 +2317,11 @@
 			strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
 			cpi->unit_number = cam_sim_unit(sim);
 			cpi->bus_id = sc->sc_unit;
-#if (__FreeBSD_version >= 700025)
 			cpi->protocol = PROTO_SCSI;
 			cpi->protocol_version = SCSI_REV_2;
 			cpi->transport = XPORT_USB;
 			cpi->transport_version = 0;
-#endif
+
 			if (sc == NULL) {
 				cpi->base_transfer_speed = 0;
 				cpi->max_lun = 0;
@@ -2468,16 +2373,12 @@
 			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
 			    ccb->ccb_h.target_lun);
 
-#if (__FreeBSD_version >= 700025)
 			cts->protocol = PROTO_SCSI;
 			cts->protocol_version = SCSI_REV_2;
 			cts->transport = XPORT_USB;
 			cts->transport_version = 0;
 			cts->xport_specific.valid = 0;
-#else
-			cts->valid = 0;
-			cts->flags = 0;	/* no disconnection, tagging */
-#endif
+
 			ccb->ccb_h.status = CAM_REQ_CMP;
 			xpt_done(ccb);
 			break;
@@ -2520,11 +2421,6 @@
 	}
 
 done:
-#if (__FreeBSD_version < 700037)
-	if (sc) {
-		mtx_unlock(&sc->sc_mtx);
-	}
-#endif
 	return;
 }
 
@@ -2533,7 +2429,7 @@
 {
 	struct umass_softc *sc = (struct umass_softc *)sim->softc;
 
-	if (sc == UMASS_GONE)
+	if (sc == NULL)
 		return;
 
 	DPRINTF(sc, UDMASS_SCSI, "CAM poll\n");
@@ -2619,7 +2515,8 @@
 		 * recovered. We return an error to CAM and let CAM
 		 * retry the command if necessary.
 		 */
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		xpt_freeze_devq(ccb->ccb_h.path, 1);
+		ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN;
 		xpt_done(ccb);
 		break;
 	}
@@ -2682,8 +2579,9 @@
 			 * usual.
 			 */
 
+			xpt_freeze_devq(ccb->ccb_h.path, 1);
 			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
-			    | CAM_AUTOSNS_VALID;
+			    | CAM_AUTOSNS_VALID | CAM_DEV_QFRZN;
 			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
 
 #if 0
@@ -2694,18 +2592,23 @@
 
 			/* the rest of the command was filled in at attach */
 
-			if (umass_std_transform(sc, ccb,
+			if ((sc->sc_transform)(sc,
 			    &sc->cam_scsi_test_unit_ready.opcode,
-			    sizeof(sc->cam_scsi_test_unit_ready))) {
+			    sizeof(sc->cam_scsi_test_unit_ready)) == 1) {
 				umass_command_start(sc, DIR_NONE, NULL, 0,
 				    ccb->ccb_h.timeout,
 				    &umass_cam_quirk_cb, ccb);
+				break;
 			}
-			break;
 		} else {
-			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
-			    | CAM_AUTOSNS_VALID;
-			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+			xpt_freeze_devq(ccb->ccb_h.path, 1);
+			if (key >= 0) {
+				ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
+				    | CAM_AUTOSNS_VALID | CAM_DEV_QFRZN;
+				ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+			} else
+				ccb->ccb_h.status = CAM_AUTOSENSE_FAIL
+				    | CAM_DEV_QFRZN;
 		}
 		xpt_done(ccb);
 		break;
@@ -2713,7 +2616,8 @@
 	default:
 		DPRINTF(sc, UDMASS_SCSI, "Autosense failed, "
 		    "status %d\n", status);
-		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
+		xpt_freeze_devq(ccb->ccb_h.path, 1);
+		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL | CAM_DEV_QFRZN;
 		xpt_done(ccb);
 	}
 }
@@ -2720,8 +2624,8 @@
 
 /*
  * This completion code just handles the fact that we sent a test-unit-ready
- * after having previously failed a READ CAPACITY with CHECK_COND.  Even
- * though this command succeeded, we have to tell CAM to retry.
+ * after having previously failed a READ CAPACITY with CHECK_COND.  The CCB
+ * status for CAM is already set earlier.
  */
 static void
 umass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
@@ -2730,9 +2634,6 @@
 	DPRINTF(sc, UDMASS_SCSI, "Test unit ready "
 	    "returned status %d\n", status);
 
-	ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
-	    | CAM_AUTOSNS_VALID;
-	ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
 	xpt_done(ccb);
 }
 
@@ -3021,7 +2922,8 @@
 		xpt_done(ccb);
 		return (0);
 	} else if (retval == 0) {
-		ccb->ccb_h.status = CAM_REQ_INVALID;
+		xpt_freeze_devq(ccb->ccb_h.path, 1);
+		ccb->ccb_h.status = CAM_REQ_INVALID | CAM_DEV_QFRZN;
 		xpt_done(ccb);
 		return (0);
 	}

Modified: trunk/sys/dev/usb/storage/urio.c
===================================================================
--- trunk/sys/dev/usb/storage/urio.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/storage/urio.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -80,7 +80,7 @@
 #ifdef USB_DEBUG
 static int urio_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio");
 SYSCTL_INT(_hw_usb_urio, OID_AUTO, debug, CTLFLAG_RW,
     &urio_debug, 0, "urio debug level");
 #endif

Modified: trunk/sys/dev/usb/template/usb_template.c
===================================================================
--- trunk/sys/dev/usb/template/usb_template.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/template/usb_template.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -845,20 +845,20 @@
 	struct usb_device_descriptor *dd;
 	uint16_t mps;
 
-	if (desc == NULL) {
+	if (desc == NULL)
 		return (USB_ERR_INVAL);
-	}
+
 	/* get bus methods */
 	methods = udev->bus->methods;
 
-	if (methods->get_hw_ep_profile == NULL) {
+	if (methods->get_hw_ep_profile == NULL)
 		return (USB_ERR_INVAL);
-	}
+
 	if (desc->bDescriptorType == UDESC_DEVICE) {
 
-		if (desc->bLength < sizeof(*dd)) {
+		if (desc->bLength < sizeof(*dd))
 			return (USB_ERR_INVAL);
-		}
+
 		dd = (void *)desc;
 
 		/* get HW control endpoint 0 profile */
@@ -905,14 +905,13 @@
 		}
 		return (0);		/* success */
 	}
-	if (desc->bDescriptorType != UDESC_CONFIG) {
+	if (desc->bDescriptorType != UDESC_CONFIG)
 		return (USB_ERR_INVAL);
-	}
-	if (desc->bLength < sizeof(*(ues->cd))) {
+	if (desc->bLength < sizeof(*(ues->cd)))
 		return (USB_ERR_INVAL);
-	}
-	ues = udev->bus->scratch[0].hw_ep_scratch;
 
+	ues = udev->scratch.hw_ep_scratch;
+
 	memset(ues, 0, sizeof(*ues));
 
 	ues->ep_max = ues->ep;
@@ -1232,14 +1231,19 @@
 {
 	struct usb_temp_setup *uts;
 	void *buf;
+	usb_error_t error;
 	uint8_t n;
+	uint8_t do_unlock;
 
-	if (tdd == NULL) {
-		/* be NULL safe */
+	/* be NULL safe */
+	if (tdd == NULL)
 		return (0);
-	}
-	uts = udev->bus->scratch[0].temp_setup;
 
+	/* Protect scratch area */
+	do_unlock = usbd_enum_lock(udev);
+
+	uts = udev->scratch.temp_setup;
+
 	memset(uts, 0, sizeof(*uts));
 
 	uts->usb_speed = udev->speed;
@@ -1251,17 +1255,24 @@
 
 	if (uts->err) {
 		/* some error happened */
-		return (uts->err);
+		goto done;
 	}
 	/* sanity check */
 	if (uts->size == 0) {
-		return (USB_ERR_INVAL);
+		uts->err = USB_ERR_INVAL;
+		goto done;
 	}
 	/* allocate zeroed memory */
 	uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO);
+	/*
+	 * Allow malloc() to return NULL regardless of M_WAITOK flag.
+	 * This helps when porting the software to non-FreeBSD
+	 * systems.
+	 */
 	if (uts->buf == NULL) {
 		/* could not allocate memory */
-		return (USB_ERR_NOMEM);
+		uts->err = USB_ERR_NOMEM;
+		goto done;
 	}
 	/* second pass */
 
@@ -1276,7 +1287,7 @@
 
 	if (uts->err) {
 		/* some error happened during second pass */
-		goto error;
+		goto done;
 	}
 	/*
 	 * Resolve all endpoint addresses !
@@ -1287,7 +1298,7 @@
 		DPRINTFN(0, "Could not resolve endpoints for "
 		    "Device Descriptor, error = %s\n",
 		    usbd_errstr(uts->err));
-		goto error;
+		goto done;
 	}
 	for (n = 0;; n++) {
 
@@ -1300,14 +1311,16 @@
 			DPRINTFN(0, "Could not resolve endpoints for "
 			    "Config Descriptor %u, error = %s\n", n,
 			    usbd_errstr(uts->err));
-			goto error;
+			goto done;
 		}
 	}
-	return (uts->err);
-
-error:
-	usb_temp_unsetup(udev);
-	return (uts->err);
+done:
+	error = uts->err;
+	if (error)
+		usb_temp_unsetup(udev);
+	if (do_unlock)
+		usbd_enum_unlock(udev);
+	return (error);
 }
 
 /*------------------------------------------------------------------------*

Modified: trunk/sys/dev/usb/wlan/if_rum.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_rum.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_rum.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -80,7 +80,7 @@
 #ifdef USB_DEBUG
 static int rum_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, rum, CTLFLAG_RW, 0, "USB rum");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, rum, CTLFLAG_RW, 0, "USB rum");
 SYSCTL_INT(_hw_usb_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0,
     "Debug level");
 #endif
@@ -120,6 +120,7 @@
     RUM_DEV(HUAWEI3COM, WUB320G),
     RUM_DEV(MELCO, G54HP),
     RUM_DEV(MELCO, SG54HP),
+    RUM_DEV(MELCO, SG54HG),
     RUM_DEV(MELCO, WLIUCG),
     RUM_DEV(MELCO, WLRUCG),
     RUM_DEV(MELCO, WLRUCGAOSS),
@@ -907,7 +908,7 @@
 			goto tr_setup;
 		}
 
-		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 		if (m == NULL) {
 			DPRINTF("could not allocate mbuf\n");
 			ifp->if_ierrors++;

Modified: trunk/sys/dev/usb/wlan/if_run.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_run.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_run.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -82,7 +82,7 @@
 
 #ifdef	RUN_DEBUG
 int run_debug = 0;
-SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
 SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
     "run debug level");
 #endif
@@ -136,6 +136,7 @@
     RUN_DEV(ASUS,		RT2870_5),
     RUN_DEV(ASUS,		USBN13),
     RUN_DEV(ASUS,		RT3070_1),
+    RUN_DEV(ASUS,		USB_N53),
     RUN_DEV(ASUS2,		USBN11),
     RUN_DEV(AZUREWAVE,		RT2870_1),
     RUN_DEV(AZUREWAVE,		RT2870_2),
@@ -209,6 +210,8 @@
     RUN_DEV(LOGITEC,		RT2870_2),
     RUN_DEV(LOGITEC,		RT2870_3),
     RUN_DEV(LOGITEC,		LANW300NU2),
+    RUN_DEV(LOGITEC,		LANW150NU2),
+    RUN_DEV(LOGITEC,		LANW300NU2S),
     RUN_DEV(MELCO,		RT2870_1),
     RUN_DEV(MELCO,		RT2870_2),
     RUN_DEV(MELCO,		WLIUCAG300N),
@@ -216,6 +219,7 @@
     RUN_DEV(MELCO,		WLIUCG301N),
     RUN_DEV(MELCO,		WLIUCGN),
     RUN_DEV(MELCO,		WLIUCGNM),
+    RUN_DEV(MELCO,		WLIUCGNM2),
     RUN_DEV(MOTOROLA4,		RT2770),
     RUN_DEV(MOTOROLA4,		RT3070),
     RUN_DEV(MSI,		RT3070_1),
@@ -2016,7 +2020,8 @@
 		wcid = 0;	/* NB: update WCID0 for group keys */
 		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
 	} else {
-		wcid = RUN_AID2WCID(associd);
+		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
+		    1 : RUN_AID2WCID(associd);
 		base = RT2860_PKEY(wcid);
 	}
 
@@ -2371,9 +2376,12 @@
 	struct run_softc *sc = ic->ic_ifp->if_softc;
 	uint8_t rate;
 	uint8_t ridx;
-	uint8_t wcid = RUN_AID2WCID(ni->ni_associd);
+	uint8_t wcid;
 	int i, j;
 
+	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
+	    1 : RUN_AID2WCID(ni->ni_associd);
+
 	if (wcid > RT2870_WCID_MAX) {
 		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
 		return;
@@ -2592,7 +2600,7 @@
 	case USB_ST_SETUP:
 tr_setup:
 		if (sc->rx_m == NULL) {
-			sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
+			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
 			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
 		}
 		if (sc->rx_m == NULL) {
@@ -2666,7 +2674,7 @@
 		}
 
 		/* copy aggregated frames to another mbuf */
-		m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 		if (__predict_false(m0 == NULL)) {
 			DPRINTF("could not allocate mbuf\n");
 			ifp->if_ierrors++;
@@ -3041,8 +3049,12 @@
 	txd->flags = qflags;
 	txwi = (struct rt2860_txwi *)(txd + 1);
 	txwi->xflags = xflags;
-	txwi->wcid = IEEE80211_IS_MULTICAST(wh->i_addr1) ?
-	    0 : RUN_AID2WCID(ni->ni_associd);
+	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+		txwi->wcid = 0;
+	} else {
+		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
+		    1 : RUN_AID2WCID(ni->ni_associd);
+	}
 	/* clear leftover garbage bits */
 	txwi->flags = 0;
 	txwi->txop = 0;

Modified: trunk/sys/dev/usb/wlan/if_uath.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_uath.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_uath.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -111,10 +111,10 @@
 #include <dev/usb/wlan/if_uathreg.h>
 #include <dev/usb/wlan/if_uathvar.h>
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, uath, CTLFLAG_RW, 0, "USB Atheros");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, uath, CTLFLAG_RW, 0, "USB Atheros");
 
 static	int uath_countrycode = CTRY_DEFAULT;	/* country code */
-SYSCTL_INT(_hw_usb_uath, OID_AUTO, countrycode, CTLFLAG_RW, &uath_countrycode,
+SYSCTL_INT(_hw_usb_uath, OID_AUTO, countrycode, CTLFLAG_RW | CTLFLAG_TUN, &uath_countrycode,
     0, "country code");
 TUNABLE_INT("hw.usb.uath.countrycode", &uath_countrycode);
 static	int uath_regdomain = 0;			/* regulatory domain */
@@ -123,7 +123,7 @@
 
 #ifdef UATH_DEBUG
 int uath_debug = 0;
-SYSCTL_INT(_hw_usb_uath, OID_AUTO, debug, CTLFLAG_RW, &uath_debug, 0,
+SYSCTL_INT(_hw_usb_uath, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uath_debug, 0,
     "uath debug level");
 TUNABLE_INT("hw.usb.uath.debug", &uath_debug);
 enum {
@@ -966,7 +966,7 @@
 		dp->sc = sc;
 		if (fillmbuf) {
 			/* XXX check maxsz */
-			dp->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+			dp->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 			if (dp->m == NULL) {
 				device_printf(sc->sc_dev,
 				    "could not allocate rx mbuf\n");
@@ -2611,7 +2611,7 @@
 	}
 	sc->sc_intrx_len += chunklen;
 
-	mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	if (mnew == NULL) {
 		DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL,
 		    "%s: can't get new mbuf, drop frame\n", __func__);

Modified: trunk/sys/dev/usb/wlan/if_upgt.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_upgt.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_upgt.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -70,12 +70,12 @@
  * Sebastien Bourdeauducq <lekernel at prism54.org>.
  */
 
-SYSCTL_NODE(_hw, OID_AUTO, upgt, CTLFLAG_RD, 0,
+static SYSCTL_NODE(_hw, OID_AUTO, upgt, CTLFLAG_RD, 0,
     "USB PrismGT GW3887 driver parameters");
 
 #ifdef UPGT_DEBUG
 int upgt_debug = 0;
-SYSCTL_INT(_hw_upgt, OID_AUTO, debug, CTLFLAG_RW, &upgt_debug,
+SYSCTL_INT(_hw_upgt, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &upgt_debug,
 	    0, "control debugging printfs");
 TUNABLE_INT("hw.upgt.debug", &upgt_debug);
 enum {
@@ -1122,6 +1122,13 @@
 	    (sizeof(struct upgt_eeprom_header) + preamble_len));
 
 	while (!option_end) {
+
+		/* sanity check */
+		if (eeprom_option >= (struct upgt_eeprom_option *)
+		    (sc->sc_eeprom + UPGT_EEPROM_SIZE)) {
+			return (EINVAL);
+		}
+
 		/* the eeprom option length is stored in words */
 		option_len =
 		    (le16toh(eeprom_option->len) - 1) * sizeof(uint16_t);
@@ -1128,6 +1135,10 @@
 		option_type =
 		    le16toh(eeprom_option->type);
 
+		/* sanity check */
+		if (option_len == 0 || option_len >= UPGT_EEPROM_SIZE)
+			return (EINVAL);
+
 		switch (option_type) {
 		case UPGT_EEPROM_TYPE_NAME:
 			DPRINTF(sc, UPGT_DEBUG_FW,
@@ -1198,7 +1209,6 @@
 		eeprom_option = (struct upgt_eeprom_option *)
 		    (eeprom_option->data + option_len);
 	}
-
 	return (0);
 }
 
@@ -1207,7 +1217,9 @@
 {
 	struct upgt_eeprom_freq3_header *freq3_header;
 	struct upgt_lmac_freq3 *freq3;
-	int i, elements, flags;
+	int i;
+	int elements;
+	int flags;
 	unsigned channel;
 
 	freq3_header = (struct upgt_eeprom_freq3_header *)data;
@@ -1219,6 +1231,9 @@
 	DPRINTF(sc, UPGT_DEBUG_FW, "flags=0x%02x elements=%d\n",
 	    flags, elements);
 
+	if (elements >= (int)(UPGT_EEPROM_SIZE / sizeof(freq3[0])))
+		return;
+
 	for (i = 0; i < elements; i++) {
 		channel = ieee80211_mhz2ieee(le16toh(freq3[i].freq), 0);
 		if (channel >= IEEE80211_CHAN_MAX)
@@ -1237,7 +1252,11 @@
 	struct upgt_eeprom_freq4_header *freq4_header;
 	struct upgt_eeprom_freq4_1 *freq4_1;
 	struct upgt_eeprom_freq4_2 *freq4_2;
-	int i, j, elements, settings, flags;
+	int i;
+	int j;
+	int elements;
+	int settings;
+	int flags;
 	unsigned channel;
 
 	freq4_header = (struct upgt_eeprom_freq4_header *)data;
@@ -1252,6 +1271,9 @@
 	DPRINTF(sc, UPGT_DEBUG_FW, "flags=0x%02x elements=%d settings=%d\n",
 	    flags, elements, settings);
 
+	if (elements >= (int)(UPGT_EEPROM_SIZE / sizeof(freq4_1[0])))
+		return;
+
 	for (i = 0; i < elements; i++) {
 		channel = ieee80211_mhz2ieee(le16toh(freq4_1[i].freq), 0);
 		if (channel >= IEEE80211_CHAN_MAX)
@@ -1272,7 +1294,8 @@
 upgt_eeprom_parse_freq6(struct upgt_softc *sc, uint8_t *data, int len)
 {
 	struct upgt_lmac_freq6 *freq6;
-	int i, elements;
+	int i;
+	int elements;
 	unsigned channel;
 
 	freq6 = (struct upgt_lmac_freq6 *)data;
@@ -1280,6 +1303,9 @@
 
 	DPRINTF(sc, UPGT_DEBUG_FW, "elements=%d\n", elements);
 
+	if (elements >= (int)(UPGT_EEPROM_SIZE / sizeof(freq6[0])))
+		return;
+
 	for (i = 0; i < elements; i++) {
 		channel = ieee80211_mhz2ieee(le16toh(freq6[i].freq), 0);
 		if (channel >= IEEE80211_CHAN_MAX)
@@ -1493,7 +1519,7 @@
 	/* create mbuf which is suitable for strict alignment archs */
 	KASSERT((pkglen + ETHER_ALIGN) < MCLBYTES,
 	    ("A current mbuf storage is small (%d)", pkglen + ETHER_ALIGN));
-	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	if (m == NULL) {
 		device_printf(sc->sc_dev, "could not create RX mbuf\n");
 		return (NULL);

Modified: trunk/sys/dev/usb/wlan/if_upgtvar.h
===================================================================
--- trunk/sys/dev/usb/wlan/if_upgtvar.h	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_upgtvar.h	2013-12-28 15:28:46 UTC (rev 6568)
@@ -451,7 +451,7 @@
 	struct upgt_memory	 sc_memory;
 
 	/* data which we found in the EEPROM */
-	uint8_t			 sc_eeprom[UPGT_EEPROM_SIZE];
+	uint8_t			 sc_eeprom[2 * UPGT_EEPROM_SIZE] __aligned(4);
 	uint16_t		 sc_eeprom_hwrx;
 	struct upgt_lmac_freq3	 sc_eeprom_freq3[IEEE80211_CHAN_MAX];
 	struct upgt_lmac_freq4	 sc_eeprom_freq4[IEEE80211_CHAN_MAX][8];

Modified: trunk/sys/dev/usb/wlan/if_ural.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_ural.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_ural.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -81,7 +81,7 @@
 #ifdef USB_DEBUG
 static int ural_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, ural, CTLFLAG_RW, 0, "USB ural");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, ural, CTLFLAG_RW, 0, "USB ural");
 SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0,
     "Debug level");
 #endif
@@ -913,7 +913,7 @@
 			goto tr_setup;
 		}
 
-		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 		if (m == NULL) {
 			DPRINTF("could not allocate mbuf\n");
 			ifp->if_ierrors++;

Modified: trunk/sys/dev/usb/wlan/if_urtw.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_urtw.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_urtw.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -61,10 +61,10 @@
 #include <dev/usb/wlan/if_urtwreg.h>
 #include <dev/usb/wlan/if_urtwvar.h>
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, urtw, CTLFLAG_RW, 0, "USB Realtek 8187L");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, urtw, CTLFLAG_RW, 0, "USB Realtek 8187L");
 #ifdef URTW_DEBUG
 int urtw_debug = 0;
-SYSCTL_INT(_hw_usb_urtw, OID_AUTO, debug, CTLFLAG_RW, &urtw_debug, 0,
+SYSCTL_INT(_hw_usb_urtw, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &urtw_debug, 0,
     "control debugging printfs");
 TUNABLE_INT("hw.usb.urtw.debug", &urtw_debug);
 enum {
@@ -89,7 +89,7 @@
 } while (0)
 #endif
 static int urtw_preamble_mode = URTW_PREAMBLE_MODE_LONG;
-SYSCTL_INT(_hw_usb_urtw, OID_AUTO, preamble_mode, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_urtw, OID_AUTO, preamble_mode, CTLFLAG_RW | CTLFLAG_TUN,
     &urtw_preamble_mode, 0, "set the preable mode (long or short)");
 TUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode);
 
@@ -1458,7 +1458,7 @@
 
 		dp->sc = sc;
 		if (fillmbuf) {
-			dp->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+			dp->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 			if (dp->m == NULL) {
 				device_printf(sc->sc_dev,
 				    "could not allocate rx mbuf\n");
@@ -3994,7 +3994,7 @@
 		noise = rx->noise;
 	}
 
-	mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	if (mnew == NULL) {
 		ifp->if_ierrors++;
 		return (NULL);

Modified: trunk/sys/dev/usb/wlan/if_zyd.c
===================================================================
--- trunk/sys/dev/usb/wlan/if_zyd.c	2013-12-28 15:28:26 UTC (rev 6567)
+++ trunk/sys/dev/usb/wlan/if_zyd.c	2013-12-28 15:28:46 UTC (rev 6568)
@@ -78,7 +78,7 @@
 #ifdef USB_DEBUG
 static int zyd_debug = 0;
 
-SYSCTL_NODE(_hw_usb, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd");
 SYSCTL_INT(_hw_usb_zyd, OID_AUTO, debug, CTLFLAG_RW, &zyd_debug, 0,
     "zyd debug level");
 
@@ -2191,9 +2191,9 @@
 		ifp->if_ierrors++;
 		return;
 	} else if (rlen > (int)MHLEN)
-		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 	else
-		m = m_gethdr(M_DONTWAIT, MT_DATA);
+		m = m_gethdr(M_NOWAIT, MT_DATA);
 	if (m == NULL) {
 		DPRINTF(sc, ZYD_DEBUG_RECV, "%s: could not allocate rx mbuf\n",
 		    device_get_nameunit(sc->sc_dev));



More information about the Midnightbsd-cvs mailing list