Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Mar 2026 16:53:43 +0000
From:      Bjoern A. Zeeb <bz@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 4c7dbe9f794f - stable/15 - usb: umass: add SCSIEJECT quirk and fix RTW8821CU_CD (USB mode switch)
Message-ID:  <69b19e17.456d1.47de9198@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=4c7dbe9f794f601c8abf791078fbe57e0a8a63e5

commit 4c7dbe9f794f601c8abf791078fbe57e0a8a63e5
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-01-26 13:19:37 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-03-11 16:53:25 +0000

    usb: umass: add SCSIEJECT quirk and fix RTW8821CU_CD (USB mode switch)
    
    Several Realtek (and lots other) USB dongles present themselves as
    CDROM device first.  Upon eject they do a mode switch and suddenly
    are a different kind of device (sometimes even with different IDs),
    e.g., a wireless dongle.
    
    In order to avoid the CDROM stage and rather than adding the quirk
    handling to more drivers, add support to umass and if enabled
    automatically eject the "CDROM" to make it the real device.
    
    Longer-term some other drivers could stop using their hand-rolled
    support for this.  It is unclear as-to how much we need the list of
    (eject) quirks from u3g here, or if these are very specific to that
    kind of devices.
    
    Sponsored by:   The FreeBSD Foundation
    Fixes:          b3b6a959c85a, 9c0cce328363
    Reviewed by:    imp
    Differential Revision: https://reviews.freebsd.org/D54901
    
    (cherry picked from commit b4daeded66b5e950ed8e618d66915b863c2414b1)
---
 sys/dev/usb/quirk/usb_quirk.c |  2 +-
 sys/dev/usb/storage/umass.c   | 57 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c
index 802ea2b2ae6a..69e16c91604f 100644
--- a/sys/dev/usb/quirk/usb_quirk.c
+++ b/sys/dev/usb/quirk/usb_quirk.c
@@ -532,7 +532,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
 	    UQ_MSC_NO_INQUIRY, UQ_CFG_INDEX_0),
 	USB_QUIRK(SMART2, G2MEMKEY, UQ_MSC_NO_INQUIRY),
 	USB_QUIRK_REV(RALINK, RT_STOR, 0x0001, 0x0001, UQ_MSC_IGNORE),
-	USB_QUIRK(REALTEK, RTW8821CU_CD, UQ_MSC_IGNORE),
+	USB_QUIRK(REALTEK, RTW8821CU_CD, UQ_MSC_EJECT_SCSIEJECT),
 	/* Non-standard USB MIDI devices */
 	USB_QUIRK(ROLAND, UM1, UQ_AU_VENDOR_CLASS),
 	USB_QUIRK(ROLAND, SC8850, UQ_AU_VENDOR_CLASS),
diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c
index cacf4ddf8f16..0ee6ea992fa7 100644
--- a/sys/dev/usb/storage/umass.c
+++ b/sys/dev/usb/storage/umass.c
@@ -115,6 +115,7 @@
 #include <sys/sx.h>
 #include <sys/unistd.h>
 #include <sys/callout.h>
+#include <sys/eventhandler.h>
 #include <sys/malloc.h>
 #include <sys/priv.h>
 
@@ -124,6 +125,7 @@
 #include "usbdevs.h"
 
 #include <dev/usb/quirk/usb_quirk.h>
+#include <dev/usb/usb_msctest.h>
 
 #include <cam/cam.h>
 #include <cam/cam_ccb.h>
@@ -705,6 +707,59 @@ static const uint8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = {
 #define	UFI_COMMAND_LENGTH	12	/* UFI commands are always 12 bytes */
 #define	ATAPI_COMMAND_LENGTH	12	/* ATAPI commands are always 12 bytes */
 
+static void
+umass_autoinst_eject_quirks(void *arg __unused, struct usb_device *udev,
+    struct usb_attach_arg *uaa)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *id;
+
+	if (uaa->dev_state != UAA_DEV_READY)
+		return;
+
+	iface = usbd_get_iface(udev, 0);
+	if (iface == NULL)
+		return;
+
+	id = iface->idesc;
+	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
+		return;
+
+	if (usb_test_quirk(uaa, UQ_MSC_EJECT_SCSIEJECT)) {
+		int error;
+
+		error = usb_msc_eject(uaa->device, 0, MSC_EJECT_STOPUNIT);
+		if (error == 0)
+			uaa->dev_state = UAA_DEV_EJECTING;
+		else
+			printf("UMASS failed to eject by SCSI eject STOPUNIT "
+			    "command based on quirk: %d\n", error);
+	}
+}
+
+static eventhandler_tag umass_drv_evh_tag;
+
+static int
+umass_driver_evh(struct module *mod, int what, void *arg)
+{
+
+	switch (what) {
+	case MOD_LOAD:
+		umass_drv_evh_tag = EVENTHANDLER_REGISTER(usb_dev_configured,
+		    umass_autoinst_eject_quirks, NULL, EVENTHANDLER_PRI_ANY);
+		break;
+	case MOD_UNLOAD:
+		if (umass_drv_evh_tag != NULL)
+			EVENTHANDLER_DEREGISTER(usb_dev_configured,
+			    umass_drv_evh_tag);
+		break;
+	default:
+		return (EOPNOTSUPP);
+	}
+
+	return (0);
+}
+
 static device_method_t umass_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, umass_probe),
@@ -725,7 +780,7 @@ static const STRUCT_USB_HOST_ID __used umass_devs[] = {
 	{USB_IFACE_CLASS(UICLASS_MASS),},
 };
 
-DRIVER_MODULE(umass, uhub, umass_driver, NULL, NULL);
+DRIVER_MODULE(umass, uhub, umass_driver, umass_driver_evh, NULL);
 MODULE_DEPEND(umass, usb, 1, 1, 1);
 MODULE_DEPEND(umass, cam, 1, 1, 1);
 MODULE_VERSION(umass, 1);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69b19e17.456d1.47de9198>