Bug #11511
closedusbsacm fails to open sigma designs device
100%
Description
This issue was found on a personal SmartOS server I am running. I have the following USB device plugged into the server: https://aeotec.com/z-wave-usb-stick. From what I understand the device presents a usb serial modem that allows you interact with the device for its intended purpose.
The physical device has some LED lights that can be toggled off via this command
echo -e -n "\x01\x08\x00\xF2\x51\x01\x00\x05\x01\x51" > /dev/cua0
However, on my SmartOS box that results in ENXIO as seen below:
open64("/devices/pci@0,0/pci15d9,400@1d/communications@2/modem@0:0,cu", O_WRONLY|O_CREAT|O_TRUNC, 0666) Err#6 ENXIO
So, I started to dig into the problem to see what I could find. Here is an information dump of what I have so far.
The device descriptor tree:
> ::prtusb -t -v -i b INDEX DRIVER INST NODE GEN VID.PID PRODUCT b usb_mid 1 communications2.0 0658.0200 No Product String usba_device: 0x84fcf000 mfg_prod_sn: NULL - NULL -NULL communications, instance #1 (driver name: usb_mid) /pci@0,0/pci15d9,400@1d/communications@2 dip: 0xf3b67008 usb_mid_statep: 0xde7d1e8 usb_mid_errlevel: 0x4 { modem, instance #0 (driver name: usbsacm) /pci@0,0/pci15d9,400@1d/communications@2/modem@0 dip: 0xd2566aa0 usbsacm_statep: 0x75591850 usbsacm_errlevel: 0x4 data, instance #-1 (driver not attached) /pci@0,0/pci15d9,400@1d/communications@2/data dip: 0x55d12010 } Device Descriptor { bLength = 0x12 bDescriptorType = 0x1 bcdUSB = 0x200 bDeviceClass = 0x2 bDeviceSubClass = 0 bDeviceProtocol = 0 bMaxPacketSize0 = 0x8 idVendor = 0x658 idProduct = 0x200 bcdDevice = 0 iManufacturer = 0 iProduct = 0 iSerialNumber = 0 bNumConfigurations = 0x1 } -- Active Config Index 0 Configuration Descriptor { bLength = 0x9 bDescriptorType = 0x2 wTotalLength = 0x43 bNumInterfaces = 0x2 bConfigurationValue = 0x1 iConfiguration = 0x0 bmAttributes = 0x80 bMaxPower = 0x32 } Interface Descriptor { bLength = 0x9 bDescriptorType = 0x4 bInterfaceNumber = 0x0 bAlternateSetting = 0x0 bNumEndpoints = 0x1 bInterfaceClass = 0x2 bInterfaceSubClass = 0x2 bInterfaceProtocol = 0x1 iInterface = 0x0 } Unknown_Interface:0x24 { 05 24 00 10 01 } Unknown_Interface:0x24 { 05 24 01 00 01 } Unknown_Interface:0x24 { 04 24 02 00 } Unknown_Interface:0x24 { 05 24 06 00 01 } Endpoint Descriptor { bLength = 0x7 bDescriptorType = 0x5 bEndpointAddress = 0x81 bmAttributes = 0x3 wMaxPacketSize = 0x8 bInterval = 0x20 } Interface Descriptor { bLength = 0x9 bDescriptorType = 0x4 bInterfaceNumber = 0x1 bAlternateSetting = 0x0 bNumEndpoints = 0x2 bInterfaceClass = 0xa bInterfaceSubClass = 0x0 bInterfaceProtocol = 0x0 iInterface = 0x0 } Endpoint Descriptor { bLength = 0x7 bDescriptorType = 0x5 bEndpointAddress = 0x82 bmAttributes = 0x2 wMaxPacketSize = 0x20 bInterval = 0x0 } Endpoint Descriptor { bLength = 0x7 bDescriptorType = 0x5 bEndpointAddress = 0x2 bmAttributes = 0x2 wMaxPacketSize = 0x20 bInterval = 0x0 }
If we trace the usbsacm_open path when attempting to echo the example above we see
# ./downstack_usbsacm.d dtrace: script './downstack_usbsacm.d' matched 1212 probes CPU FUNCTION 14 -> usbsacm_open genunix`qattach+0xf6 genunix`stropen+0x347 specfs`spec_open+0x379 genunix`fop_open+0x91 genunix`vn_openat+0x234 genunix`copen+0x204 genunix`openat64+0x2a genunix`open64+0x25 unix`_sys_sysenter_post_swapgs+0x153 14 | usbsacm_open:entry 14 -> usbser_open 14 -> usbser_open_setup 14 -> usbser_open_init 14 -> usbser_check_port_props 14 <- usbser_check_port_props Returns 0x0 14 -> usbser_thr_dispatch 14 <- usbser_thr_dispatch Returns 0x0 14 -> usbser_thr_dispatch 14 <- usbser_thr_dispatch Returns 0x0 14 -> usbsacm_ds_open_port 14 -> usbsacm_pm_set_busy 14 <- usbsacm_pm_set_busy Returns 0x0 14 -> usbsacm_open_port_pipes 14 -> usb_lookup_ep_data 14 <- usb_lookup_ep_data Returns 0xfffffede8c72fab0 14 -> usb_lookup_ep_data 14 <- usb_lookup_ep_data Returns 0xfffffee1a1c5e280 14 -> usb_lookup_ep_data 14 <- usb_lookup_ep_data Returns 0xfffffee1a1c5e2a0 14 -> usb_pipe_open 14 -> usb_pipe_xopen 14 -> usba_get_usba_device 14 -> usba_is_root_hub 14 <- usba_is_root_hub Returns 0x0 14 <- usba_get_usba_device Returns 0xfffffee184fcf000 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x12 14 -> usba_init_pipe_handle 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 <- usba_init_pipe_handle Returns 0x0 14 -> usba_hcdi_get_data_toggle 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x12 14 <- usba_hcdi_get_data_toggle Returns 0x0 14 -> usba_pipe_new_state 14 <- usba_pipe_new_state Returns 0x0 14 <- usb_pipe_xopen Returns 0x0 14 <- usb_pipe_open Returns 0x0 14 -> usb_pipe_open 14 -> usb_pipe_xopen 14 -> usba_get_usba_device 14 -> usba_is_root_hub 14 <- usba_is_root_hub Returns 0x0 14 <- usba_get_usba_device Returns 0xfffffee184fcf000 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x2 14 -> usba_init_pipe_handle 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 <- usba_init_pipe_handle Returns 0x0 14 -> usba_hcdi_get_data_toggle 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x2 14 <- usba_hcdi_get_data_toggle Returns 0x0 14 -> usba_pipe_new_state 14 <- usba_pipe_new_state Returns 0x0 14 <- usb_pipe_xopen Returns 0x0 14 <- usb_pipe_open Returns 0x0 14 -> usb_pipe_open 14 -> usb_pipe_xopen 14 -> usba_get_usba_device 14 -> usba_is_root_hub 14 <- usba_is_root_hub Returns 0x0 14 <- usba_get_usba_device Returns 0xfffffee184fcf000 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x11 14 -> usba_init_pipe_handle 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 <- usba_init_pipe_handle Returns 0x0 14 -> usba_hcdi_get_data_toggle 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x11 14 <- usba_hcdi_get_data_toggle Returns 0x0 14 -> usba_pipe_new_state 14 <- usba_pipe_new_state Returns 0x0 14 <- usb_pipe_xopen Returns 0x0 14 <- usb_pipe_open Returns 0x0 14 -> usbsacm_pipe_start_polling 14 -> usb_alloc_intr_req 14 -> usba_req_wrapper_alloc 14 -> usba_get_usba_device 14 -> usba_is_root_hub 14 <- usba_is_root_hub Returns 0x0 14 <- usba_get_usba_device Returns 0xfffffee184fcf000 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_add_to_list 14 <- usba_add_to_list Returns 0x0 14 <- usba_req_wrapper_alloc Returns 0xfffffee08a2a5c70 14 <- usb_alloc_intr_req Returns 0xfffffee08a2a5d00 14 -> usb_pipe_intr_xfer 14 -> usba_hold_ph_data 14 <- usba_hold_ph_data Returns 0xfffffef2dd1bb078 14 -> usba_check_req 14 -> usba_check_in_list 14 <- usba_check_in_list Returns 0x0 14 -> usba_flags_attr_check 14 <- usba_flags_attr_check Returns 0x0 14 <- usba_check_req Returns 0x0 14 -> usba_get_ph_state 14 <- usba_get_ph_state Returns 0x1 14 -> usba_pipe_new_state 14 <- usba_pipe_new_state Returns 0x0 14 -> usba_hcdi_dup_intr_req 14 -> usb_alloc_intr_req 14 -> usba_req_wrapper_alloc 14 -> usba_get_usba_device 14 -> usba_is_root_hub 14 <- usba_is_root_hub Returns 0x0 14 <- usba_get_usba_device Returns 0xfffffee184fcf000 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_add_to_list 14 <- usba_add_to_list Returns 0xfffffee08a2a5ca0 14 <- usba_req_wrapper_alloc Returns 0xfffffee3c5b7b2d0 14 <- usb_alloc_intr_req Returns 0xfffffee3c5b7b360 14 <- usba_hcdi_dup_intr_req Returns 0xfffffee3c5b7b360 14 -> usba_release_ph_data 14 <- usba_release_ph_data Returns 0x0 14 <- usb_pipe_intr_xfer Returns 0x0 14 <- usbsacm_pipe_start_polling Returns 0x0 14 <- usbsacm_open_port_pipes Returns 0x0 14 -> usbsacm_rx_start 14 -> usb_alloc_bulk_req 14 -> usba_req_wrapper_alloc 14 -> usba_get_usba_device 14 -> usba_is_root_hub 14 <- usba_is_root_hub Returns 0x0 14 <- usba_get_usba_device Returns 0xfffffee184fcf000 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_init_list 14 <- usba_init_list Returns 0x0 14 -> usba_add_to_list 14 <- usba_add_to_list Returns 0xfffffee3c5b7b300 14 <- usba_req_wrapper_alloc Returns 0xfffffee3c43fb710 14 <- usb_alloc_bulk_req Returns 0xfffffee3c43fb7a0 14 -> usb_pipe_bulk_xfer 14 -> usba_hold_ph_data 14 <- usba_hold_ph_data Returns 0xfffffedfcebd1330 14 -> usba_check_req 14 -> usba_check_in_list 14 <- usba_check_in_list Returns 0x0 14 -> usba_flags_attr_check 14 <- usba_flags_attr_check Returns 0x0 14 <- usba_check_req Returns 0x0 14 -> usba_get_ph_state 14 <- usba_get_ph_state Returns 0x1 14 -> usba_pipe_new_state 14 <- usba_pipe_new_state Returns 0x0 14 -> usba_release_ph_data 14 <- usba_release_ph_data Returns 0x0 14 <- usb_pipe_bulk_xfer Returns 0x0 14 <- usbsacm_rx_start Returns 0x0 14 <- usbsacm_ds_open_port Returns 0x0 14 -> usbser_port_program 14 -> usbsacm_ds_set_port_params 14 -> usb_dprintf2 14 -> usba_vlog 14 -> usb_vprintf 14 <- usb_vprintf Returns 0xfffffeddf24b00b9 14 <- usba_vlog Returns 0x0 14 <- usb_dprintf2 Returns 0x0 14 <- usbsacm_ds_set_port_params Returns 0xffffffff 14 <- usbser_port_program Returns 0x16 14 <- usbser_open_init Returns 0x6 14 -> usbser_open_fini 14 -> usbsacm_ds_close_port 14 -> usbsacm_close_port_pipes 14 -> usb_pipe_reset 14 -> usba_hold_ph_data 14 <- usba_hold_ph_data Returns 0xfffffedfcebd1330 14 -> usba_check_intr_context 14 <- usba_check_intr_context Returns 0x0 14 -> usba_pipe_setup_func_call 14 -> usba_pipe_sync_reset 14 -> usba_get_ph_data 14 <- usba_get_ph_data Returns 0xfffffedfcebd1330 14 -> usb_dprintf2 14 -> usba_vlog 14 -> usb_vprintf 14 <- usb_vprintf Returns 0xfffffeddf24b00e8 14 <- usba_vlog Returns 0x0 14 <- usb_dprintf2 Returns 0x0 14 -> usb_dprintf2 14 -> usba_vlog 14 -> usb_vprintf 14 <- usb_vprintf Returns 0xfffffeddf24b0130 14 <- usba_vlog Returns 0x0 14 <- usb_dprintf2 Returns 0x0 14 -> usba_hcdi_cb 14 -> usba_hcdi_get_hcdi 14 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 14 -> usba_add_to_list 14 <- usba_add_to_list Returns 0x0 14 -> usba_async_ph_req 14 <- usba_async_ph_req Returns 0x0 14 <- usba_hcdi_cb Returns 0x0 14 -> usba_drain_cbs 14 -> usba_rm_first_pvt_from_list 14 -> usba_rm_first_from_list 14 <- usba_rm_first_from_list Returns 0x0 14 <- usba_rm_first_pvt_from_list Returns 0x0 14 -> usba_list_entry_count 14 <- usba_list_entry_count Returns 0x0 1 -> usba_list_entry_count 1 <- usba_list_entry_count Returns 0x0 1 <- usba_drain_cbs Returns 0x0 1 -> usba_pipe_new_state 1 <- usba_pipe_new_state Returns 0x0 1 -> usba_start_next_req 1 -> usba_get_ph_state 1 <- usba_get_ph_state Returns 0x1 1 -> usba_rm_first_pvt_from_list 1 -> usba_rm_first_from_list 1 <- usba_rm_first_from_list Returns 0x0 1 <- usba_rm_first_pvt_from_list Returns 0x0 1 <- usba_start_next_req Returns 0x0 1 -> usba_release_ph_data 1 <- usba_release_ph_data Returns 0x0 1 <- usba_pipe_sync_reset Returns 0x0 1 <- usba_pipe_setup_func_call Returns 0x0 1 <- usb_pipe_reset Returns 0x0 1 -> usb_pipe_close 1 -> usba_check_intr_context 1 <- usba_check_intr_context Returns 0x0 1 -> usba_hold_ph_data 1 <- usba_hold_ph_data Returns 0xfffffedfcebd1330 1 -> usba_pipe_setup_func_call 1 -> usba_pipe_sync_close 1 -> usba_get_ph_data 1 <- usba_get_ph_data Returns 0xfffffedfcebd1330 1 -> usba_hcdi_set_data_toggle 1 -> usb_get_ep_index 1 <- usb_get_ep_index Returns 0x12 1 <- usba_hcdi_set_data_toggle Returns 0x0 1 -> usba_destroy_pipe_handle 1 -> usba_destroy_list 1 <- usba_destroy_list Returns 0xfffffee195fa6c46 1 -> usba_destroy_list 1 <- usba_destroy_list Returns 0xfffffee195fa6c46 1 <- usba_destroy_pipe_handle Returns 0xfffffee3d54b7940 1 <- usba_pipe_sync_close Returns 0x0 1 <- usba_pipe_setup_func_call Returns 0x0 1 <- usb_pipe_close Returns 0x0 1 -> usb_pipe_close 1 -> usba_check_intr_context 1 <- usba_check_intr_context Returns 0x0 1 -> usba_hold_ph_data 1 <- usba_hold_ph_data Returns 0xfffffee3d913d3e0 1 -> usba_pipe_setup_func_call 1 -> usba_pipe_sync_close 1 -> usba_get_ph_data 1 <- usba_get_ph_data Returns 0xfffffee3d913d3e0 1 -> usba_hcdi_set_data_toggle 1 -> usb_get_ep_index 1 <- usb_get_ep_index Returns 0x2 1 <- usba_hcdi_set_data_toggle Returns 0x0 1 -> usba_destroy_pipe_handle 1 -> usba_destroy_list 1 <- usba_destroy_list Returns 0xfffffee195fa6c46 1 -> usba_destroy_list 1 <- usba_destroy_list Returns 0xfffffee195fa6c46 1 <- usba_destroy_pipe_handle Returns 0xfffffee3d54b7940 1 <- usba_pipe_sync_close Returns 0x0 1 <- usba_pipe_setup_func_call Returns 0x0 1 <- usb_pipe_close Returns 0x0 1 -> usb_pipe_stop_intr_polling 1 -> usba_hold_ph_data 1 <- usba_hold_ph_data Returns 0xfffffef2dd1bb078 1 -> usba_pipe_setup_func_call 1 -> usba_pipe_sync_stop_intr_polling 1 -> usba_get_ph_data 1 <- usba_get_ph_data Returns 0xfffffef2dd1bb078 1 -> usba_get_ph_state 1 <- usba_get_ph_state Returns 0x2 1 -> usba_get_ph_state 1 <- usba_get_ph_state Returns 0x2 1 -> usba_hcdi_set_data_toggle 1 -> usb_get_ep_index 1 <- usb_get_ep_index Returns 0x11 1 <- usba_hcdi_set_data_toggle Returns 0x0 1 -> usb_free_intr_req 1 -> usba_req_wrapper_free 1 -> usba_rm_from_list 1 <- usba_rm_from_list Returns 0xffffffff 1 -> usba_get_usba_device 1 -> usba_is_root_hub 1 <- usba_is_root_hub Returns 0x0 1 <- usba_get_usba_device Returns 0xfffffee184fcf000 1 -> usba_rm_from_list 1 <- usba_rm_from_list Returns 0x0 1 -> usba_destroy_list 1 <- usba_destroy_list Returns 0xfffffee195fa6c46 1 -> usba_destroy_list 1 <- usba_destroy_list Returns 0xfffffee195fa6c46 1 <- usba_req_wrapper_free Returns 0xfffffee3d54b7940 1 <- usb_free_intr_req Returns 0xfffffee3d54b7940 1 -> usba_hcdi_cb 1 -> usba_hcdi_get_hcdi 1 <- usba_hcdi_get_hcdi Returns 0xfffffede1caad558 1 -> usba_add_to_list 1 <- usba_add_to_list Returns 0x0 1 -> usba_async_ph_req 1 <- usba_async_ph_req Returns 0x0 1 <- usba_hcdi_cb Returns 0x0 1 -> usba_drain_cbs 1 -> usba_rm_first_pvt_from_list 1 -> usba_rm_first_from_list 1 <- usba_rm_first_from_list Returns 0x0 1 <- usba_rm_first_pvt_from_list Returns 0x0 1 -> usba_list_entry_count 1 <- usba_list_entry_count Returns 0x0 14 -> usba_list_entry_count 14 <- usba_list_entry_count Returns 0x0 14 <- usba_drain_cbs Returns 0x0 14 -> usba_release_ph_data 14 <- usba_release_ph_data Returns 0x0 14 <- usba_pipe_sync_stop_intr_polling Returns 0x0 14 <- usba_pipe_setup_func_call Returns 0x0 14 <- usb_pipe_stop_intr_polling Returns 0x0 14 -> usb_pipe_close 14 -> usba_check_intr_context 14 <- usba_check_intr_context Returns 0x0 14 -> usba_hold_ph_data 14 <- usba_hold_ph_data Returns 0xfffffef2dd1bb078 14 -> usba_pipe_setup_func_call 14 -> usba_pipe_sync_close 14 -> usba_get_ph_data 14 <- usba_get_ph_data Returns 0xfffffef2dd1bb078 14 -> usba_hcdi_set_data_toggle 14 -> usb_get_ep_index 14 <- usb_get_ep_index Returns 0x11 14 <- usba_hcdi_set_data_toggle Returns 0x0 14 -> usba_destroy_pipe_handle 14 -> usba_destroy_list 14 <- usba_destroy_list Returns 0xfffffee195fa6c46 14 -> usba_destroy_list 14 <- usba_destroy_list Returns 0xfffffee195fa6c46 14 <- usba_destroy_pipe_handle Returns 0xfffffee3d708c580 14 <- usba_pipe_sync_close Returns 0x0 14 <- usba_pipe_setup_func_call Returns 0x0 14 <- usb_pipe_close Returns 0x0 14 <- usbsacm_close_port_pipes Returns 0x0 14 -> usbsacm_fifo_flush_locked 14 <- usbsacm_fifo_flush_locked Returns 0x0 14 -> usbsacm_pm_set_idle 14 <- usbsacm_pm_set_idle Returns 0x0 14 <- usbsacm_ds_close_port Returns 0x0 14 -> usbser_thr_cancel 14 <- usbser_thr_cancel Returns 0x0 14 -> usbser_thr_cancel 14 <- usbser_thr_cancel Returns 0x0 14 <- usbser_open_fini Returns 0x0 14 <- usbser_open_setup Returns 0x6 14 <- usbser_open Returns 0x6 14 <- usbsacm_open Returns 0x6
Digging through the above output I see that the call to usbsacm_ds_set_port_params()
is returning -1 aka USB_FAILURE
. Judging by the flow trace that function takes it looks like we we might not be getting passed this check.
/* * If device conform to acm spec, check if it support to set port param. */ if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 && acmp->acm_compatibility == B_TRUE) { mutex_exit(&acm_port->acm_port_mutex); USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, "usbsacm_ds_set_port_params: " "don't support Set_Line_Coding."); return (USB_FAILURE); }
Since this box is not running a DEBUG build I snooped in on the logs with this dtrace line and confirmed we are indeed returning USB_FAILURE there.
# dtrace -n 'usb_vprintf:entry {print(stringof(args[3]))}' | grep usbsacm dtrace: description 'usb_vprintf:entry ' matched 1 probe 12 59311 usb_vprintf:entry string "usbsacm_ds_set_port_params: don't support Set_Line_Coding."
Next I wanted to see where the acm_cap member of the usbsacm_port_t was coming from which happens to be in usbsacm_get_descriptors on line 1721: http://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/io/usb/clients/usbser/usbsacm/usbsacm.c#1721
So next I printed out the contents of the usb_alt_if_data_t structure grabbing its address with:
#!/usr/sbin/dtrace -s usbsacm_get_descriptors:entry { this->acmp = args[0]; /* print(this->acmp); */ this->acm_port = this->acmp->acm_ports; this->cfg = this->acmp->acm_dev_data->dev_curr_cfg; this->altif = this->cfg->cfg_if[this->acm_port->acm_ctrl_if_no].if_alt[0]; print(this->altif); }
Which gives us:
# ./zwave_attach.d dtrace: script './zwave_attach.d' matched 1 probe CPU ID FUNCTION:NAME 15 62983 usbsacm_get_descriptors:entry struct usb_alt_if_data { usb_if_descr_t altif_descr = { uint8_t bLength = 0x9 uint8_t bDescriptorType = 0x4 uint8_t bInterfaceNumber = 0 uint8_t bAlternateSetting = 0 uint8_t bNumEndpoints = 0x1 uint8_t bInterfaceClass = 0x2 uint8_t bInterfaceSubClass = 0x2 uint8_t bInterfaceProtocol = 0x1 uint8_t iInterface = 0 } struct usb_ep_data *altif_ep = 0xfffffede96dceb58 struct usb_cvs_data *altif_cvs = 0xfffffede5a4e0040 char *altif_str = 0xfffffedef7d38b88 uint_t altif_n_ep = 0x1 uint_t altif_n_cvs = 0x4 uint_t altif_strsize = 0x7 }
> 0xfffffede5a4e0040,4::print "struct usb_cvs_data" { cvs_buf = 0xfffffef2d6368de8 cvs_buf_len = 0x5 } { cvs_buf = 0xfffffee3ddc290b0 cvs_buf_len = 0x5 } { cvs_buf = 0xfffffedf55cc1038 cvs_buf_len = 0x4 } { cvs_buf = 0xfffffedf55c9e3b8 cvs_buf_len = 0x5 }
If we look at the 3rd member we see
> 0xfffffedf55cc1038,4/V 0xfffffedf55cc1038: 4 36 2 0
We know the code checks for USB_CDC_DESCR_TYPE_ACM
when setting up acm_port->acm_cap which is defined as 0x02. So the buffer I dumped above shows USB_CDC_DESCR_TYPE_ACM
in the field the code is switching over aka cvs->cvs_buf2. The code then sets the field like so: acm_port->acm_cap = cvs->cvs_buf[3];
Which we can see in the above output is "0".
I can manually modify this field with mdb and verify that I can toggle the LED lights on and off on the physical device. I am also able to confirm that the real technical features of the device function as expected.
addr/W 2
Some relavant info from a linux box where the device works:
[377981.025628] usb 1-4: new full-speed USB device number 4 using xhci_hcd [377981.345033] usb 1-4: New USB device found, idVendor=0658, idProduct=0200, bcdDevice= 0.00 [377981.345036] usb 1-4: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [377981.362847] cdc_acm 1-4:1.0: ttyACM0: USB ACM device [377981.365070] usbcore: registered new interface driver cdc_acm [377981.365071] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
$ sudo lsusb -D /dev/bus/usb/001/004 Device: ID 0658:0200 Sigma Designs, Inc. Aeotec Z-Stick Gen5 (ZW090) - UZB Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 2 Communications bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x0658 Sigma Designs, Inc. idProduct 0x0200 Aeotec Z-Stick Gen5 (ZW090) - UZB bcdDevice 0.00 iManufacturer 0 iProduct 0 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0043 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 1 CDC ACM: bmCapabilities 0x00 CDC Union: bMasterInterface 0 bSlaveInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 0 can't get device qualifier: Resource temporarily unavailable can't get debug descriptor: Resource temporarily unavailable Device Status: 0x0000 (Bus Powered)
The descriptors seem to match up perfectly from with what each OS is reading from the device.
Since Linux reports CDC ACM
as 0x00
it seems that the Linux driver doesn't have the same issue we do.
Updated by Michael Zeller about 3 years ago
Robert Mustacchi noted the following:
"It appears that the major difference between us and the other operating systems is that we care about that particular capability. The rest basically still try to set it regardless of whether or not that flag says they should or shouldn't. It appears Linux will more explicitly warn about that case when it fails. We may want to consider just not having that check there and warning about it if it fails when that's not there. I suspect that the impact of such a change isn't terribly high."
Updated by Jorge Schrauwen about 3 years ago
I also have a zwave usb stick, but from a different vendor: https://z-wave.me/uzb/
This one also identifies as the same device, as the design is open they all share the same chips from silabs.
https://www.silabs.com/products/development-tools/software/z-wave
Updated by Michael Zeller about 3 years ago
Testing notes from https://www.illumos.org/rb/r/2206/ :
Built and ran this patch on a SmartOS platform and confirmed that the USB device was successfully able to control z-wave devices on my network. I also had two more community members, sjorge and bahamas10, confirm that it made their devices function correctly as well. Bahamas10 and I have the same USB device while sjorge has another device using the same Sigma Designs, Inc chip.
Updated by Electric Monk about 3 years ago
- Status changed from In Progress to Closed
- % Done changed from 0 to 100
git commit 8072728215ff40bc56f6ad193cd22da6fbc03bc6
commit 8072728215ff40bc56f6ad193cd22da6fbc03bc6 Author: Mike Zeller <mike@mikezeller.net> Date: 2019-08-05T16:53:04.000Z 11511 usbsacm fails to open sigma designs device Reviewed by: Joshua M. Clulow <josh@sysmgr.org> Reviewed by: Gergő Doma <domag02@gmail.com> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Dan McDonald <danmcd@joyent.com>