From this the status phase of a control transfer happens after the data phase (in or out) so I think you should be able to handle the setup request, look at the data and then return a stall or an ack. In the above example the device is returning data over endpoint 0 but it should be the same for the device receiving data.

I modified the CyFxBulkLpApplnUSBSetupCB function to handle my own vendor commands. If a vendor command is detected within CyFxBulkLpApplnUSBSetupCB it calls my function to handle the vendor requests. If this vendor function returns false the CyFxBulkLpApplnUSBSetupCB sets the stall bit. I modified one of my vendor commands to check the downloaded payload data and if the value of the first byte was 2 the vendor function returned false. I tried this code using Cypress Control center and if the payload data contained the value 2 I got the error messageCONTROL OUT transfer failed with Error Code:997 So I think this works. I understand that the APIGuide is saying only one type of API call is allowed, however this appears to be different from the example code that Cypress show handling the setup request in firmware where you send data using CyU3PUsbSendEP0Data and if this is not successful you can use the CyU3PUsbStall function

When you registered the callback function CyFxBulkLpApplnUSBSetupCB was fast enumeration set to false see below

I pasted your code into the USBBulkLoopAutoEnum with no other changes and the control transfer fails if I send the value 2 in the payload data with error code 997. With any other value the control transfer is susscessful. I am running this on a 32 bit Windows XP machine. I changed the value to 3 and compiled again and this time the control transfer failed on the value 3. I''ve attached the compiled .img file if you would like to try this - fails on 3