Dear Canonical Kernel Team,

I ran several tests yesterday and the bug seems to be fixed now, my USB
FM transmitter works again!

Tests done on Ubuntu Jammy Jellyfish:
Kernel version        Test result
<=5.15.0-89           OK (=device works)
5.15.0-92             KO (=USB device not enumerated)
-93 -> -138           KO
5.15.0-139            KO
>=5.15.0-140          OK

So first, what I suspected in my previous comment appears to be true.
The bug appears right after the -89 patch, in a similar context as what
I observed on Ubuntu Focal Fossa with the kernels 5.4.0-167 and
5.4.0-169.

I then tried to understand why the bug disappeared in -140 patch by
analyzing differences in source code. So I downloaded linux-
source-5.15.0_5.15.0-89.99_all.deb, linux-
source-5.15.0_5.15.0-92.102_all.deb, linux-
source-5.15.0_5.15.0-139.149_all.deb and linux-
source-5.15.0_5.15.0-140.150_all.deb, and extracted them to review the
code.

I first understood that I was misled in the original bug report due to
the changelogs of the patches which are not exhaustive at all. The
changes between -89 and -92 are huge and do not only correct bug
#2043197. So the piece of code I mentioned was actually not the culprit.

I think I found the problem by analyzing the differences between -139 and -140 
source code. According to the differences seen in the kernel logs between a 
working configuration and a failing configuration, I focused on the USB port 
initialization mechanism found in the file drivers/usb/core/hub.c.
As far as I understood, an asynchronous event (like plugging the USB device) 
triggers the hub_port_connect function. This function loops 4 times on 
hub_port_init function, twice with the new scheme (get_descriptor with a 64 
byte request), then powers down/up the device, and twice with the old scheme 
(set_address and reads 8 bytes of the device descriptor to get the EP0 max 
packet size).

In a working configuration, the USB connection process goes like this with my 
device:
hub_port_connect
        do_new_scheme (returns !old_scheme_first_port)
        hub_port_init
                maxp0=-32 -> device descriptor read/64 error
                maxp0=-32 -> device descriptor read/64 error
        hub_port_init
                maxp0=-32 -> device descriptor read/64 error
                maxp0=-32 -> device descriptor read/64 error
        hub_port_power_cycle
        !do_new_scheme (returns old_scheme_first_port)
        hub_port_init
                hub_set_address -> device not accepting address error
        hub_port_init
Device is recognized.

In a failing configuration, the USB connection process goes like this:
hub_port_connect
        do_new_scheme (returns !old_scheme_first_port)
        hub_port_init
                maxp0=-32 -> device descriptor read/64 error
                maxp0=-32 -> device descriptor read/64 error
        hub_port_init
                maxp0=-32 -> device descriptor read/64 error
                maxp0=-32 -> device descriptor read/64 error
        hub_port_power_cycle
        !do_new_scheme (returns old_scheme_first_port)
        hub_port_init
                maxp0=-32 -> device descriptor read/8 error
                maxp0=-32 -> device descriptor read/8 error
        hub_port_init
                maxp0=-32 -> device descriptor read/8 error
                maxp0=-32 -> device descriptor read/8 error
Device is not enumerated.

So the problem is the maxp0 value is wrong, it should be 8 with the old
scheme. It is returned by the get_bMaxPacketSize0 function and the code
of this function has changed between -139 and -140 patch, especially
these parts:

$ diff -u linux-source-5.15.0_5.15.0-139.149_all/usr/src/linux-
source-5.15.0/linux-source-5.15.0/drivers/usb/core/hub.c linux-
source-5.15.0_5.15.0-140.150_all/usr/src/linux-source-5.15.0/linux-
source-5.15.0/drivers/usb/core/hub.c

(...)

@@ -4673,7 +4684,6 @@
 EXPORT_SYMBOL_GPL(usb_ep0_reinit);
 
 #define usb_sndaddr0pipe()     (PIPE_CONTROL << 30)
-#define usb_rcvaddr0pipe()     ((PIPE_CONTROL << 30) | USB_DIR_IN)
 
 static int hub_set_address(struct usb_device *udev, int devnum)
 {

(...)

@@ -4774,7 +4784,7 @@
        for (i = 0; i < GET_MAXPACKET0_TRIES; ++i) {
                /* Start with invalid values in case the transfer fails */
                buf->bDescriptorType = buf->bMaxPacketSize0 = 0;
-               rc = usb_control_msg(udev, usb_rcvaddr0pipe(),
+               rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                                USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                                USB_DT_DEVICE << 8, 0,
                                buf, size,

(...)

The use of usb_rcvaddr0pipe macro has been replaced by macro
usb_rcvctrlpipe which uses endpoint device number in the USB control
pipe, according to commit
https://github.com/torvalds/linux/commit/4aac0db5a0ebc599d4ad9bf5ebab78afa1f33e10

So I am not 100% sure but I really suspect this change to solve the bug!

Best regards.


** Changed in: linux (Ubuntu)
       Status: New => Fix Released

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2100787

Title:
  USB FM transmitter not recognized after kernel update

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2100787/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to