AnsweredAssumed Answered

How to make a USB HID device NAK or STALL requests

Question asked by Gareth McCaughan on Jul 27, 2017

[I asked a version of this question in the Kinetis Microcontrollers forum, having failed to find this forum. If for any reason you care, here's a link to that question.]

 

Background: I'm using a KL26 MCU, and I'm still on version 1.3.0 of the KSDK. (But an answer that begins "First, move to a more recent SDK version" is better than none at all :-).) I'm making a USB HID device. It runs at the hilariously-misnamed "full speed".

 

Under some circumstances (more details available on request, but I don't think they're important) I would like my device to respond to get/set-report requests (I don't care what happens to other requests) with a NAK, so that the host will retry a little later. Alternatively, stalling the relevant endpoints would do.

 

I haven't found anything in the documentation indicating how to do this, nor anything indicating explicitly that it's impossible.

 

All my application's code is written in terms of the USB_Class_HID_... API; in particular, I begin by calling USB_Class_HID_Init and interact with the USB stack mostly through the class-specific callback registered at that point, and my code never sees a usb_device_handle that it could pass to lower-level functions like usb_device_stall_endpoint.

 

So, it seems like any of the following three things would accomplish my goals. (1) Arrange for the USB hardware to know that we're busy and to reply to USB transactions with a NAK at the setup stage. (2) Arrange for a NAK response in the status stage of the transaction. (3) Arrange for a STALL response in the status or data stage of the transaction.

 

Of these, #1 can't be done "per request" because by the time control reaches the relevant callback the setup stage has already been handled by the hardware. #2 and #3 seem like they possibly could be -- or, like #1, they might be arranged by informing the USB stack that we're busy.

 

There are functions in the KSDK that should make #3 happen: usb_device_stall_endpoint and usb_device_unstall_endpoint. However, these require a usb_device_handle, and because my code is talking to the HID level of the stack it never sees one of those, only a hid_handle_t. (Behind the scenes, a hid_handle_t is "really" a pointer to a structure that contains a usb_device_handle; but there's a typedef in the way to make it opaque and I take this as a warning that client code is not supposed to go diving into lower layers. For all I know, the HID code may not take kindly to having its endpoint stalled.)

 

I haven't found anything that seems like it would make #1 or #2 happen, but it seems possible that there might be something that one can do in the class-specific callback that would accomplish #2. Glancing at the SDK source code, I think the value returned from the callback is thrown away and has no effect, but perhaps writing something suitable to *pSize might do it? Or perhaps something suitable is already in *pSize and leaving it alone would suffice?

 

I can do some experiments with a USB analyser, but for obvious reasons I would prefer my code to be based on something more solid than "I tried this and it seemed to work" :-). The ideal would be if there's a documented way to do this that I've just failed to find. Next best would be something undocumented but well understood by people more expert than me and known to be safe.

 

Thanks!

Outcomes