Default USB Device Reaction to Invalid Vendor Request on FX2 and FX2LP

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
dwaggone
Level 1
Level 1
5 sign-ins First reply posted First question asked

Hello,

I'm curious to know if it should be possible to send an invalid vendor request code to the Default USB device on an FX2[LP]. I know that the request code 0xa0 is always recognized before and after renumeration. I attempted to send another code that is implemented in our firmware to the default USB device and I expected that it would simply reject the request and stall endpoint 0. In our Windows driver when I attempted to send a URB that packages that vendor request, USBD seems to block indefinitely. After seeing that, I put in logic to cancel the IRP after a timeout elapsed. However, when I went to continue through our usual process of downloading firmware, it seems to malfunction, as if it consumed part of my invalid vendor request and cached it before processing the subsequent 0xa0 vendor request.

Is this just something I should completely avoid doing [sending unrecognized vendor request codes to it]? I managed to move on to a different technique but my motivation was to try to discern between our device having renumerated with firmware and a fresh firmware-less enumeration state. Granted, one can use vendor, product, and device ID combinations to deduce this, but this was something of an academic exercise for me and I'm genuinely curious. I could not find anything in the TRM that would tell me what to expect under this scenario.

~Thanks

0 Likes
1 Solution
Pranava_YN
Moderator
Moderator
Moderator
100 likes received 500 replies posted 250 solutions authored

Hi,

Yes, invalid vendor commands can be sent to default USB device and device will stall the endpoint 0. This stall will be automatically cleared upon next setup packet arrival. therefore it should not be affecting the firmware download.

As per USB 2.0 spec "A protocol STALL is returned during the Data or Status stage of a control transfer, and the STALL condition terminates at the beginning of the next control transfer (Setup). " https://www.usb.org/document-library/usb-20-specification Page no. 207

Same is implemented and stated in the FX2LP TRM [Page no. 39] "If the firmware stalls endpoint zero (by setting the STALL and HSNAK bits to 1), the EZ-USB automatically clears the stall bit when the next SETUP token arrives."

Can you please clarify whether you are using CYUSB3 driver or any other custom driver?

 

Best regards,
Pranava

View solution in original post

4 Replies
Pranava_YN
Moderator
Moderator
Moderator
100 likes received 500 replies posted 250 solutions authored

Hi,

Yes, invalid vendor commands can be sent to default USB device and device will stall the endpoint 0. This stall will be automatically cleared upon next setup packet arrival. therefore it should not be affecting the firmware download.

As per USB 2.0 spec "A protocol STALL is returned during the Data or Status stage of a control transfer, and the STALL condition terminates at the beginning of the next control transfer (Setup). " https://www.usb.org/document-library/usb-20-specification Page no. 207

Same is implemented and stated in the FX2LP TRM [Page no. 39] "If the firmware stalls endpoint zero (by setting the STALL and HSNAK bits to 1), the EZ-USB automatically clears the stall bit when the next SETUP token arrives."

Can you please clarify whether you are using CYUSB3 driver or any other custom driver?

 

Best regards,
Pranava
dwaggone
Level 1
Level 1
5 sign-ins First reply posted First question asked

Hi Pranava,

Thank you for taking the time to respond. We have a custom WDM-based driver that we have deployed for many years, and I recently took over as the main developer for it, though I was familiar with many of its workings before that. 

Here is a slightly modified version of code I was attempting. Some of these are helper routines but they're broadly deployed with other parts of the code base and don't seem to have any known problems. The URB seems to block indefinitely when I call this before our firmware is running (or any has been downloaded), whereas I expected it to return almost immediately if endpoint 0 stalls. Hence why I added the timeout and cancellation of the IRP after some time. This code was intended to be called very shortly after the device enumerates and is noticed by Windows, and additionally on demand by way of a device IOCTL from a diagnostic application we have.

 

 

    NTSTATUS
    OurDriver_IsRenumerated
    (
        DEVICE_OBJECT * const p_do,
        BOOLEAN       * const p_response
    )
    {
        NTSTATUS r = STATUS_SUCCESS;
        
        // Clarification: underlying type is _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
        URB * const urb = OurDriver_AllocateVendorRequestUrb
        (
            CUSTOM_VENDOR_REQUEST_TAG
        );
        
        // -----------------------------
        
        if(urb)
        {
            UCHAR xfer_buffer[2] = { 0 };
            
            // -----------------------------
            
            OurDriver_PrepareVendorRequestUrb
            (
                urb,
                (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK),
                xfer_buffer,
                sizeof(xfer_buffer),
                VR_OURDRIVER_IS_RENUMERATED,
                0, // request's value
                0  // request's index
            );
            
            r = OurDriver_CallUSBD_WithTimeout
            (
                p_do,
                urb,
                (1000 * 1000) * 1 // (1 second, currently)
            );
            
            if( NT_SUCCESS(r) )
            {
                USHORT const magic_number = Get_LittleEndian_16Bit(xfer_buffer);
                
                // -----------------------------
                
                (*p_response) =
                (
                    (magic_number == OURDRIVER_MAGIC)
                  ? TRUE
                  : FALSE
                );
            }
        }
        else
        {
            r = STATUS_NO_MEMORY;
        }
        
        // Clean up.
        if(urb)
        {
            OurDriver_ExFreePoolWithTag
            (
                urb,
                CUSTOM_VENDOR_REQUEST_TAG
            );
        }
        
        return r;
    }

 

 

I'm not here to have everything spoon-fed to me so of course if you have a document or section of a document to point me to that would give me an idea of what to do I'd be just as happy. Of note is that this is an IN transfer, and the underlying vendor request code is 0xc2 [of no relation to a 0xc2 boot EEPROM load, it's just coincidence]. Currently we do not call this function upon enumeration (or renumeration) because it I couldn't get it to work the way I wanted. Are we supposed to do something on the host side to clear the stall? Is there something one must do in Windows drivers to detect that a stall has occurred? Notwithstanding this, I pondered for several weeks whether to even ask this question at all so I will have to re-enable it to remind myself of the exact way this seems to screw with firmware downloads.

At the risk of being a nuisance by asking an additional unrelated question, but for me it is a burning one for several months: Is it expected behavior that the 0xa0 vendor request seems to work properly regardless of whether the CPU is held in reset when the target RAM region is 0xe000 to 0xe1ff? A long time ago we accidentally noticed that it just seems to work but I couldn't find this documented in the TRM.

0 Likes
Pranava_YN
Moderator
Moderator
Moderator
100 likes received 500 replies posted 250 solutions authored

Hi,

 

Since control transfers are blocking the URB is probably struck/ retrying the transfer. As you have implemented, setting a timeout is one possible way to recover from this on the host side. Initiating next control transfer to EP0 should clear stall on host side as well. 

You can find CYUSB3 driver source code here - https://www.cypress.com/file/289981/download

It will be helpful to analyze if you can share USB logs during this condition and failed firmware downloads. 

 Regarding behavior of FX2LP to 0xA0 command, that vendor command is handled in FX2LP by SIE (Serial Interface Engine). Therefore it is required to keep CPU in reset so that FW execution is not affected till complete RAM write. Since the region you are referring to is scratchpad RAM, sometimes it might not cause any issue even if CPU is not held in reset. But it is definitely recommended to hold CPU in reset until write is complete.

Best regards,
Pranava
dwaggone
Level 1
Level 1
5 sign-ins First reply posted First question asked

I will definitely take a look at that driver code, and thanks for the clarification on holding in reset. Naturally there would be a race condition, but I was thinking perhaps that the default device might be able to latch that XDATA region, whereas perhaps reading from main RAM might be masked off or open bus. When I don't hold the CPU in reset and try to read the main RAM (0x0000-0x3fff) I get what looks more or less like garbage or noise.

At any rate thanks very much for your insights!

0 Likes