I'm going to preface this by saying that I'm stuck for now (at least for some projects) on CodeWarrior 10.6, so using KSDK isn't an option. I'm using the Freescale USB stack v4.1.1 because as far as I know it's the most recent version that's compatible with CW 10.6. I've used it on HCS08, ColdFire, and Kinetis. I have products with ColdFire and Kinetis versions that have to be maintained in parallel so I'm stuck with this stack. I know it's no longer supported and I'm posting this mainly to get a solution out there for anyone else in a similar situation.
I spent hours trying to get a simple MSD+CDC composite device running on a MK22FN1M0. I started with the msd_and_cdc example under app_composite. I ran into a couple of problems right way - first, if USE_CDC_CLASS is defined, then the DFU class is also included as well, for no apparent reason. I think this was probably a case of someone cutting and pasting code without paying attention:
I got rid of that and then found that there's no function declaration for USB_Class_CDC_Event() in scope. Why the compiler allows implicit function declarations by default I'll never understand, but I fixed that as well.
The MSD function worked fine right off. CDC, however, let me connect successfully once and maybe on one or two other occasions. Every other time, with any terminal program (on both Windows and Ubuntu), it'd fail - on Windows, the error message was some variation of "the parameter is incorrect", depending on the program used.
With a USB sniffer I could see that the GET_LINE_CODING setup packets were being sent from the host but no proper replies were ever being received. I finally determined that the problem is in USB_Composite_Other_Requests(). It iterates through the list of classes and it's checking to see if the interface number matches, but it will also match if the endpoint number is not 0xff:
if(itf_num == intf_arc_ptr->value[index] || ep_num != 0xFF)
Since ep_num is initialized to 0 at the start of the function and is only changed if the setup packet specified an endpoint as the destination and not an interface, this check always succeeds and every setup packet handler for any registered class receives every request. For classes with more than one interface, the handler is called once for each interface. This explains why I was seeing two GET_LINE_CODING requests for every connect attempt.
As far as I can tell, the only way this would have ever worked at all was just sheer luck. The status result will be overwritten on the return of each handler so it would often return USBERR_INVALID_REQ_TYPE. I can't imagine what kind of trouble it might cause with other combinations of composite device.
The fix came down to just changing the initialization of ep_num to 0xff. (After fixing the function declaration and the DFU ifdef.)
This code was written two mergers ago so I'm going to skip the rant, except to ask whoever's running the show now to please consider having a native (or at least very fluent) English speaker make at least a cursory pass through all English-language documentation and code comments. I've got nothing against foreign programmers, but most programmers are bad enough at writing documentation in their native language. "The funtion initializes composite endpoint" is not a good description of a function.
A quick sanity check on anything copied and pasted would also be appreciated. The very first line in usb_composite.c is this:
#include "usb_composite.h" /* USB Video Class Header File */
Ok, rant over. I hope maybe this saves someone else some headaches.