Hi there! I'm working on a device that's currently setup as a USB mass storage device. Now I've added HID functionality as per the following descriptor:
/* USB Configuration Descriptor */ /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor) */ const U8 USB_ConfigDescriptor[] = { /* Configuration 1 */ USB_CONFIGUARTION_DESC_SIZE, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL( /* wTotalLength */ 1*USB_CONFIGUARTION_DESC_SIZE + 2*USB_INTERFACE_DESC_SIZE + HID_DESC_SIZE + 4*USB_ENDPOINT_DESC_SIZE ), 0x02, /* bNumInterfaces */ 0x01, /* bConfigurationValue: 0x01 is used to select this configuration */ 0x04, /* iConfiguration */ USB_CONFIG_BUS_POWERED /* bmAttributes */ USB_CONFIG_POWER_MA(100), /* bMaxPower, device power consumption is 100 mA */ /* Interface 0, Alternate Setting 0, HID Class */ USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x02, /* bNumEndpoints */ USB_DEVICE_CLASS_HUMAN_INTERFACE, /* bInterfaceClass */ HID_SUBCLASS_NONE, /* bInterfaceSubClass */ HID_PROTOCOL_NONE, /* bInterfaceProtocol */ 0x05, /* iInterface */ /* HID Class Descriptor */ /* HID_DESC_OFFSET = 0x0012 */ HID_DESC_SIZE, /* bLength */ HID_HID_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL(0x0100), /* 1.00 */ /* bcdHID */ 0x00, /* bCountryCode */ 0x01, /* bNumDescriptors */ HID_REPORT_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL(HID_REPORT_DESC_SIZE), /* wDescriptorLength */ /* Endpoint, EP1 Interrupt IN */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_IN(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ WBVAL(0x0040), /* wMaxPacketSize */ 0x20, /* 32ms */ /* bInterval */ /* Endpoint, EP1 Interrupt OUT */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_OUT(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ WBVAL(0x0040), /* wMaxPacketSize */ 0x20, /* 32ms */ /* bInterval */ /* Interface 1, Alternate Setting 0, MSC Class */ USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x01, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x02, /* bNumEndpoints */ USB_DEVICE_CLASS_STORAGE, /* bInterfaceClass */ MSC_SUBCLASS_SCSI, /* bInterfaceSubClass */ MSC_PROTOCOL_BULK_ONLY, /* bInterfaceProtocol */ 0x07, /* iInterface */ /* Endpoint, EP2 Bulk IN */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_IN(2), /* bEndpointAddress */ USB_ENDPOINT_TYPE_BULK, /* bmAttributes */ WBVAL(0x0040), /* wMaxPacketSize */ 0x00, /* bInterval: ignore for Bulk transfer */ /* Endpoint, EP2 Bulk OUT */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_OUT(2), /* bEndpointAddress */ USB_ENDPOINT_TYPE_BULK, /* bmAttributes */ WBVAL(0x0040), /* wMaxPacketSize */ 0x00, /* bInterval: ignore for Bulk transfer */ /* Terminator */ 0 /* bLength */ };
This works fine. However, I'd rather be able to turn the MSC on and off at runtime. Now I don't know what's the best way to do so. Looks two me like my options are: use two configurations or use two alternate interfaces...
<continued in the next post>
The interface number of the MSC interface should be 1
/* Interface 0, Alternate Setting 1, MSC Class */ ... 0x00, /* bInterfaceNumber */ // <--- 0x01 (or USB_MSC_IF_NUM)
Did you touch to usbcfg.h, too?
usbcfg.h #define USB_IF_NUM 1 // <--- 2 #define USB_EP_EVENT 0x0003 // <--- 0x0007 #define USB_CLASS 1 #define USB_HID 1 #define USB_HID_IF_NUM 0 #define USB_MSC 0 // <--- 1 #define USB_MSC_IF_NUM 0 // <--- 1
> What would be the best way to create a runtime-configurable USB device? In the best case by switching between its modes on the device itself (as opposed to sending some USB command).
USB spec allows that a device may have two or more configurations. However, OS (especially Windows) doesn't support configurations switch well. A composite device, as you did, is practical in most cases.
Tsuneo
Thanks for the advice regarding OSs. So I'm dropping the idea of using different configurations and focusing on using alternate settings.
> The interface number of the MSC interface should be 1 Should it? I thought the whole point of using alternate settings is to share the interface (Axelson: "When a configuration supports multiple, mutually exclusive interfaces, each of the interfaces has a descriptor with the same value in bInterfaceNumber and a unique value in bAlternateSetting"). That's also why my usbcfg looks like this, with USB_HID_IF_NUM==USB_MSC_IF_NUM:
#define USB_POWER 0 #define USB_IF_NUM 1 #define USB_EP_NUM 32 #define USB_MAX_PACKET0 8 #define USB_DMA 0 #define USB_DMA_EP 0x00000000 #define USB_POWER_EVENT 1 #define USB_RESET_EVENT 1 #define USB_SUSPEND_EVENT 0 #define USB_RESUME_EVENT 0 #define USB_WAKEUP_EVENT 0 #define USB_SOF_EVENT 0 #define USB_ERROR_EVENT 0 #define USB_EP_EVENT 0x0007 #define USB_CONFIGURE_EVENT 1 #define USB_INTERFACE_EVENT 1 #define USB_FEATURE_EVENT 0 #define USB_CLASS 1 #define USB_HID 1 #define USB_HID_IF_NUM 0 #define USB_MSC 1 #define USB_MSC_IF_NUM 0 #define USB_AUDIO 0 #define USB_ADC_CIF_NUM 0 #define USB_ADC_SIF1_NUM 1 #define USB_ADC_SIF2_NUM 2 #define USB_CDC 0 #define USB_CDC_CIF_NUM 0 #define USB_CDC_DIF_NUM 1 #define USB_CDC_BUFSIZE 64 #define USB_VENDOR 0
Besides, if I set USB_MSC_IF_NUM to 1, I'm back to the composite device which works fine, but doesn't allow me to turn off the MSC.
Ah, you want to switch HID/MSC using alternate interface, but it can't. Alternate interface(s) should have the same interface class as the default interface. Alternate interface is supposed to change endpoints, not the interface class.
9.6.5 Interface (usb_20.pdf) An interface may include alternate settings that allow the endpoints and/or their characteristics to be varied after the device has been configured.
You don't like composite device. Then, another option is soft-detach / swap descriptors / soft attach. You have to swap all descriptors including the device descriptor, to assign another VID/PID to the device. If the MSC would have the same VID/PID as HID, Windows should get confused.