Changing the interface number of devices of a composite device

I have a project am I working on which is 3 HID devices and 1 CDC device. That is working just fine. It is a composite device so everything has its own interface(3 for HID, and 2 for CDC) however the problem I have been having is that I need a specific order of these devices. I need the CDC device to come after the 3 hid devices but it seems no matter what I do, the CDC device makes itself use interface 0 and 1. I have tried unregistering and registering after the HID setup but that does work. I tried changing the INIT priorities, I've tried a bunch of weird stuff in the device tree overlay and I am at a loss. Has anyone done this before successfully? I am using the new USB stack btw. 

// Initialize USB HID composite device
int usb_hid_composite_init(void)
{
    struct usbd_context *sample_usbd;
    int err;

    sample_usbd = sample_usbd_init_device(NULL);
    if (sample_usbd == NULL)
    {
        // LOG_ERR("Failed to initialize USB device");
        return -ENODEV;
    }

    LOG_INF("Waiting 5 seconds for serial monitor connection...");
    k_sleep(K_SECONDS(5));

    LOG_INF("Attempting to unregister CDC ACM before USB enable");
    err = usbd_unregister_class(sample_usbd, "cdc_acm_uart0", USBD_SPEED_FS, 1);
    if (err == 0) {
        LOG_INF("Successfully unregistered cdc_acm_uart0 before enable");
    } else {
        LOG_WRN("Failed to unregister cdc_acm_uart0 before enable: %d", err);
    }

    // reset_usb();

    hid_mouse = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(hid_mouse));
    hid_keyboard = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(hid_keyboard));
    hid_gamepad = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(hid_gamepad));

    if (hid_mouse == NULL)
    {
        // LOG_ERR("Cannot get USB HID Device");
        return -ENODEV;
    }

    hid_device_register(hid_mouse,
                        mouse_report_desc, sizeof(mouse_report_desc),
                        &ops);

    hid_device_register(hid_keyboard,
                        keyboard_report_desc, sizeof(keyboard_report_desc),
                        &ops);

    hid_device_register(hid_gamepad,
                        gamepad_report_desc, sizeof(gamepad_report_desc),
                        &ops);

    err = usbd_register_class(sample_usbd, "cdc_acm_uart0", USBD_SPEED_FS, 1);


    usbd_device_set_vid(sample_usbd, 0x1234); // xxxx VID
    usbd_device_set_pid(sample_usbd, 0x1234); // xxxx PID



    err = usbd_enable(sample_usbd);
    if (err)
    {
        // LOG_ERR("Failed to enable device support");
        return err;
    }

    // LOG_ERR("*** USB HID composite device initialized - DS4 Feature Reports Ready ***");
    return 0;
}

Parents
  • CONFIG_USB_DEVICE_STACK_NEXT=y
    CONFIG_USB_DEVICE_STACK=n
    CONFIG_USBD_HID_SUPPORT=y
    
    CONFIG_LOG=y
    CONFIG_USBD_LOG_LEVEL_WRN=y
    CONFIG_USBD_HID_LOG_LEVEL_WRN=y
    CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
    
    CONFIG_SAMPLE_USBD_MANUFACTURER="xxx"
    CONFIG_SAMPLE_USBD_PRODUCT="xxxx"
    CONFIG_SAMPLE_USBD_MAX_POWER=250
    CONFIG_SAMPLE_USBD_20_EXTENSION_DESC=y
    CONFIG_SAMPLE_USBD_SELF_POWERED=n
    
    CONFIG_GPIO=y
    CONFIG_INPUT=y
    
    # Enhanced ShockBurst configuration
    CONFIG_ESB=y
    CONFIG_UART_CONSOLE=n
    CONFIG_USBD_CDC_ACM_CLASS=y
    ##CONFIG_USBD_HID_INIT_PRIORITY=01 this didn't do anything
    
    # Prevent CDC ACM from auto-registering at boot
    CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n

    here is my prj.conf btw. I also tried setting CONFIG_USBD_CDC_ACM_CLASS=n and then registering with what I declared in my device tree but CDC won't work at all that way

Reply
  • CONFIG_USB_DEVICE_STACK_NEXT=y
    CONFIG_USB_DEVICE_STACK=n
    CONFIG_USBD_HID_SUPPORT=y
    
    CONFIG_LOG=y
    CONFIG_USBD_LOG_LEVEL_WRN=y
    CONFIG_USBD_HID_LOG_LEVEL_WRN=y
    CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
    
    CONFIG_SAMPLE_USBD_MANUFACTURER="xxx"
    CONFIG_SAMPLE_USBD_PRODUCT="xxxx"
    CONFIG_SAMPLE_USBD_MAX_POWER=250
    CONFIG_SAMPLE_USBD_20_EXTENSION_DESC=y
    CONFIG_SAMPLE_USBD_SELF_POWERED=n
    
    CONFIG_GPIO=y
    CONFIG_INPUT=y
    
    # Enhanced ShockBurst configuration
    CONFIG_ESB=y
    CONFIG_UART_CONSOLE=n
    CONFIG_USBD_CDC_ACM_CLASS=y
    ##CONFIG_USBD_HID_INIT_PRIORITY=01 this didn't do anything
    
    # Prevent CDC ACM from auto-registering at boot
    CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n

    here is my prj.conf btw. I also tried setting CONFIG_USBD_CDC_ACM_CLASS=n and then registering with what I declared in my device tree but CDC won't work at all that way

Children
  • Hello,

    I received this suggestion from one of our developers:

    "sample_usbd_init_device()should not be used in this case. Copy the contents of sample_usbd_init_device() to the application, and replace usbd_register_all_classes() with the individual class registrations in the desired order.

    Class removal after calling sample_usbd_init_device() does not work because the interfaces and endpoints are assigned in usbd_init() -> usbd_device_init_core() -> usbd_init_configurations() -> init_configuration(), and usbd_init() is called inside sample_usbd_init_device()"

    Hope this helps.

    Best regards,

    Vidar

Related