I am looking at coding a USB device that is capable of encapsulating two USB devices. I would like to create a HID keyboard with a single extra USB port. A mass storage device would be connected to the port.

I was wondering, would I be able to program the keyboard to register it as a composite device encapsulating the mass storage and the keyboard?

My current thought process is to declare the keyboard as having 2 interfaces. I was thinking of simply copying the USB commands from the mass drive into one of the interfaces of the keyboard. Is this possible?

If this is incorrect thinking, please let me know what the data formatting of the interfaces is suppose to be.

Thank you.

Also, this is for educational purposes to expand my knowledge of USB.

  • \$\begingroup\$ It be easier to use a hardware usb hub ic then trying to do a usb hub in composite. So of these ICs only need a cap and crystal. \$\endgroup\$ – Passerby Sep 15 '18 at 0:12

You can't have a "HID keyboard" with a "single extra port"; the device of this kind must be a compound device, made of a two-port hub, with one port connected to non-removable HID device. The other port can be permanently connected to a mass-storage device. In this case you might not need to wrap all this as a composite device (a device supporting two alternative classes).

Designing correct set of descriptors for these kind of devices is awfully complicated (at least from a hardware guy perspective), but you can use ready-to-go guides from, say, Keil compiler support, MDK Middleware for USB Device and Host Communication. This link is for an example of composite USB device built upon two their previous tutorials, "USB Device HID", and "USB Device mass storage". I hope this is exactly what you need.

  • \$\begingroup\$ Hello. Thank you for your reply. Thank you for the resource. I will be taking a look at it later. However, i am wondering, why must it be a compund device? My understanding so far is that a comprosite device can allow the ability of 2 usb devices to appear as 1 through the interface. Is this understanding incorrect? \$\endgroup\$ – philm Sep 15 '18 at 0:57
  • 1
    \$\begingroup\$ @philm, I guess I wasn't clear that you have two ways, composite and compound. Since you said "extra USB port", this would be a path for compound device, when both functions are available at the same time over embedded hub. The advantage would be to use all standard host drivers for this device. If you want the mass storage function hidden and have it by switching interfaces of a composite device, you likely would need a proprietary driver. \$\endgroup\$ – Ale..chenski Sep 15 '18 at 1:30
  • \$\begingroup\$ Oh ok, that clears it up. So under what conditions should I use the composite device vs compound device and vice versa? \$\endgroup\$ – philm Sep 15 '18 at 2:49
  • 2
    \$\begingroup\$ @philm, compound devices are usually made of discrete controller ICs, I believe it is generally impossible to synthesize a USB hub within a MCU. If you have a just a MCU, then the composite is the only way to go. \$\endgroup\$ – Ale..chenski Sep 15 '18 at 3:10
  • \$\begingroup\$ Yes, again, this is only for education. I was reading an article where I could implement a TLC and reference each USB device through a report id. To me, this seems like a simple enough solution instead of using the interfaces which, by the sound of it, would be a pain in the butt. \$\endgroup\$ – philm Sep 15 '18 at 3:27

I've made many such composite devices (HID + mass storage) earlier, but not anymore. There are two problems. The first is that Windows doesn't like them any more. There's a ton of problems today with communicating with composite mass storage endpoints. They worked fine in Windows 2000 and Windows XP, but not so much anymore. I have no idea why - perhaps someone can educate me?

The second problem is that if you declare a mass storage device as part of your composite device descriptor, then your microcontroller code must handle the mass storage device requests. You cannot just relay them to another USB port byte by byte since the interface descriptors are (almost certainly) different. You can do this if you have another USB host port in your MCU: write USB host code that communicates with the USB flash stick (or even a totally different memory device such as SD card) and relay the block read and write commands between your composite interface and the other memory device. It'll work, at least with Linux and older Windows kernels.

But if you just want to have a simple USB port on the side of your keyboard, and you don't have any extra requirements (such as the keyboard being able to read the USB flash memory without the PC), then just grab a USD0.3 USB hub IC, put it on the same PCB, wire one of the ports to your microcontroller and the other(s) to external connector(s) in your product. The benefit is that your product is then standard, e.g. any kind of USB device(s) can be connected to the external port(s), including more hubs, and you have zero trouble with your MCU software.

[Edit] hmm... I got to thinking... I guess it could be possible to relay the MSC protocol commands (the USBC - data - USBS packets) to the other USB port, which would make the overall software implementation easier... but the other problems remain.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.