Open aquette opened 9 years ago
I have a UPS that is not officially supported. I want to try to reverse engineer (although I have never done this in practice) the proprietary application that communicates via USB with the UPS. Would these scripts be helpful in any way to do this?
hwinfo --usb
#....
13: USB 00.1: 0000 Unclassified device
[Created at usb.122]
Unique ID: yLyY.+wqcmQaR_Y7
Parent ID: W5SY.d7FDLX76qXB
SysFS ID: /devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3/usb3/3-6/3-6.1/3-6.1:1.1
SysFS BusID: 3-6.1:1.1
Hardware Class: unknown
Model: "Lakeview MCU VIRTUAL COM DEMO"
Hotplug: USB
Vendor: usb 0x0925 "Lakeview Research"
Device: usb 0x1241 "MCU VIRTUAL COM DEMO"
Revision: "1.01"
Driver: "cdc_acm"
Driver Modules: "cdc_acm"
Speed: 12 Mbps
Module Alias: "usb:v0925p1241d0101dc02dsc00dp00ic0Aisc00ip00in01"
Config Status: cfg=new, avail=yes, need=no, active=unknown
Attached to: #25 (Hub)
#....
udevadm info -a /dev/ttyACM0
``` Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3/usb3/3-6/3-6.1/3-6.1:1.0/tty/ttyACM0': KERNEL=="ttyACM0" SUBSYSTEM=="tty" DRIVER=="" ATTR{power/async}=="disabled" ATTR{power/control}=="auto" ATTR{power/runtime_active_kids}=="0" ATTR{power/runtime_active_time}=="0" ATTR{power/runtime_enabled}=="disabled" ATTR{power/runtime_status}=="unsupported" ATTR{power/runtime_suspended_time}=="0" ATTR{power/runtime_usage}=="0" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3/usb3/3-6/3-6.1/3-6.1:1.0': KERNELS=="3-6.1:1.0" SUBSYSTEMS=="usb" DRIVERS=="cdc_acm" ATTRS{authorized}=="1" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceClass}=="02" ATTRS{bInterfaceNumber}=="00" ATTRS{bInterfaceProtocol}=="00" ATTRS{bInterfaceSubClass}=="02" ATTRS{bNumEndpoints}=="01" ATTRS{bmCapabilities}=="6" ATTRS{power/async}=="enabled" ATTRS{power/runtime_active_kids}=="0" ATTRS{power/runtime_enabled}=="enabled" ATTRS{power/runtime_status}=="suspended" ATTRS{power/runtime_usage}=="0" ATTRS{supports_autosuspend}=="1" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3/usb3/3-6/3-6.1': KERNELS=="3-6.1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="02" ATTRS{bDeviceProtocol}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="100mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 2" ATTRS{bcdDevice}=="0101" ATTRS{bmAttributes}=="c0" ATTRS{busnum}=="3" ATTRS{configuration}=="" ATTRS{devnum}=="6" ATTRS{devpath}=="6.1" ATTRS{idProduct}=="1241" ATTRS{idVendor}=="0925" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="NXP SEMICONDUCTORS" ATTRS{maxchild}=="0" ATTRS{power/active_duration}=="757724" ATTRS{power/async}=="enabled" ATTRS{power/autosuspend}=="2" ATTRS{power/autosuspend_delay_ms}=="2000" ATTRS{power/connected_duration}=="757724" ATTRS{power/control}=="on" ATTRS{power/level}=="on" ATTRS{power/persist}=="1" ATTRS{power/runtime_active_kids}=="0" ATTRS{power/runtime_active_time}=="757540" ATTRS{power/runtime_enabled}=="forbidden" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="1" ATTRS{product}=="MCU VIRTUAL COM DEMO" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{rx_lanes}=="1" ATTRS{speed}=="12" ATTRS{tx_lanes}=="1" ATTRS{urbnum}=="10424" ATTRS{version}==" 2.00" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3/usb3/3-6': KERNELS=="3-6" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="09" ATTRS{bDeviceProtocol}=="01" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="100mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="8536" ATTRS{bmAttributes}=="e0" ATTRS{busnum}=="3" ATTRS{configuration}=="" ATTRS{devnum}=="3" ATTRS{devpath}=="6" ATTRS{idProduct}=="0608" ATTRS{idVendor}=="05e3" ATTRS{ltm_capable}=="no" ATTRS{maxchild}=="4" ATTRS{physical_location/dock}=="no" ATTRS{physical_location/horizontal_position}=="left" ATTRS{physical_location/lid}=="no" ATTRS{physical_location/panel}=="front" ATTRS{physical_location/vertical_position}=="upper" ATTRS{power/active_duration}=="7712304" ATTRS{power/async}=="enabled" ATTRS{power/autosuspend}=="0" ATTRS{power/autosuspend_delay_ms}=="0" ATTRS{power/connected_duration}=="7713292" ATTRS{power/control}=="auto" ATTRS{power/level}=="auto" ATTRS{power/runtime_active_kids}=="2" ATTRS{power/runtime_active_time}=="7712258" ATTRS{power/runtime_enabled}=="enabled" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="0" ATTRS{power/wakeup}=="disabled" ATTRS{power/wakeup_abort_count}=="" ATTRS{power/wakeup_active}=="" ATTRS{power/wakeup_active_count}=="" ATTRS{power/wakeup_count}=="" ATTRS{power/wakeup_expire_count}=="" ATTRS{power/wakeup_last_time_ms}=="" ATTRS{power/wakeup_max_time_ms}=="" ATTRS{power/wakeup_total_time_ms}=="" ATTRS{product}=="USB2.0 Hub" ATTRS{quirks}=="0x0" ATTRS{removable}=="removable" ATTRS{rx_lanes}=="1" ATTRS{speed}=="480" ATTRS{tx_lanes}=="1" ATTRS{urbnum}=="140" ATTRS{version}==" 2.00" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3/usb3': KERNELS=="usb3" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{authorized_default}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="09" ATTRS{bDeviceProtocol}=="01" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="0mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="0605" ATTRS{bmAttributes}=="e0" ATTRS{busnum}=="3" ATTRS{configuration}=="" ATTRS{devnum}=="1" ATTRS{devpath}=="0" ATTRS{idProduct}=="0002" ATTRS{idVendor}=="1d6b" ATTRS{interface_authorized_default}=="1" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Linux 6.5.0-21-generic xhci-hcd" ATTRS{maxchild}=="6" ATTRS{power/active_duration}=="7712796" ATTRS{power/async}=="enabled" ATTRS{power/autosuspend}=="0" ATTRS{power/autosuspend_delay_ms}=="0" ATTRS{power/connected_duration}=="7713744" ATTRS{power/control}=="auto" ATTRS{power/level}=="auto" ATTRS{power/runtime_active_kids}=="1" ATTRS{power/runtime_active_time}=="7712985" ATTRS{power/runtime_enabled}=="enabled" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="0" ATTRS{power/wakeup}=="disabled" ATTRS{power/wakeup_abort_count}=="" ATTRS{power/wakeup_active}=="" ATTRS{power/wakeup_active_count}=="" ATTRS{power/wakeup_count}=="" ATTRS{power/wakeup_expire_count}=="" ATTRS{power/wakeup_last_time_ms}=="" ATTRS{power/wakeup_max_time_ms}=="" ATTRS{power/wakeup_total_time_ms}=="" ATTRS{product}=="xHCI Host Controller" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{rx_lanes}=="1" ATTRS{serial}=="0000:08:00.3" ATTRS{speed}=="480" ATTRS{tx_lanes}=="1" ATTRS{urbnum}=="61" ATTRS{version}==" 2.00" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0/0000:08:00.3': KERNELS=="0000:08:00.3" SUBSYSTEMS=="pci" DRIVERS=="xhci_hcd" ATTRS{ari_enabled}=="0" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x0c0330" ATTRS{consistent_dma_mask_bits}=="64" ATTRS{current_link_speed}=="16.0 GT/s PCIe" ATTRS{current_link_width}=="16" ATTRS{d3cold_allowed}=="1" ATTRS{dbc}=="disabled" ATTRS{dbc_bInterfaceProtocol}=="01" ATTRS{dbc_bcdDevice}=="0010" ATTRS{dbc_idProduct}=="0010" ATTRS{dbc_idVendor}=="1d6b" ATTRS{device}=="0x149c" ATTRS{dma_mask_bits}=="64" ATTRS{driver_override}=="(null)" ATTRS{enable}=="1" ATTRS{irq}=="40" ATTRS{link/l0s_aspm}=="0" ATTRS{link/l1_aspm}=="0" ATTRS{local_cpulist}=="0-23" ATTRS{local_cpus}=="00ffffff" ATTRS{max_link_speed}=="16.0 GT/s PCIe" ATTRS{max_link_width}=="16" ATTRS{msi_bus}=="1" ATTRS{msi_irqs/59}=="msix" ATTRS{msi_irqs/60}=="msix" ATTRS{msi_irqs/61}=="msix" ATTRS{msi_irqs/62}=="msix" ATTRS{msi_irqs/63}=="msix" ATTRS{msi_irqs/64}=="msix" ATTRS{msi_irqs/65}=="msix" ATTRS{msi_irqs/66}=="msix" ATTRS{numa_node}=="-1" ATTRS{power/async}=="enabled" ATTRS{power/control}=="on" ATTRS{power/runtime_active_kids}=="1" ATTRS{power/runtime_active_time}=="7714032" ATTRS{power/runtime_enabled}=="forbidden" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="1" ATTRS{power/wakeup}=="enabled" ATTRS{power/wakeup_abort_count}=="0" ATTRS{power/wakeup_active}=="0" ATTRS{power/wakeup_active_count}=="0" ATTRS{power/wakeup_count}=="0" ATTRS{power/wakeup_expire_count}=="0" ATTRS{power/wakeup_last_time_ms}=="0" ATTRS{power/wakeup_max_time_ms}=="0" ATTRS{power/wakeup_total_time_ms}=="0" ATTRS{power_state}=="D0" ATTRS{reset_method}=="pm" ATTRS{revision}=="0x00" ATTRS{subsystem_device}=="0x148c" ATTRS{subsystem_vendor}=="0x1022" ATTRS{vendor}=="0x1022" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0/0000:03:08.0': KERNELS=="0000:03:08.0" SUBSYSTEMS=="pci" DRIVERS=="pcieport" ATTRS{ari_enabled}=="0" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x060400" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{current_link_speed}=="16.0 GT/s PCIe" ATTRS{current_link_width}=="16" ATTRS{d3cold_allowed}=="1" ATTRS{device}=="0x57a4" ATTRS{dma_mask_bits}=="32" ATTRS{driver_override}=="(null)" ATTRS{enable}=="2" ATTRS{irq}=="37" ATTRS{local_cpulist}=="0-23" ATTRS{local_cpus}=="00ffffff" ATTRS{max_link_speed}=="16.0 GT/s PCIe" ATTRS{max_link_width}=="16" ATTRS{msi_bus}=="1" ATTRS{msi_irqs/37}=="msi" ATTRS{numa_node}=="-1" ATTRS{power/async}=="enabled" ATTRS{power/autosuspend_delay_ms}=="100" ATTRS{power/control}=="auto" ATTRS{power/runtime_active_kids}=="3" ATTRS{power/runtime_active_time}=="7714038" ATTRS{power/runtime_enabled}=="enabled" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="0" ATTRS{power/wakeup}=="disabled" ATTRS{power/wakeup_abort_count}=="" ATTRS{power/wakeup_active}=="" ATTRS{power/wakeup_active_count}=="" ATTRS{power/wakeup_count}=="" ATTRS{power/wakeup_expire_count}=="" ATTRS{power/wakeup_last_time_ms}=="" ATTRS{power/wakeup_max_time_ms}=="" ATTRS{power/wakeup_total_time_ms}=="" ATTRS{power_state}=="D0" ATTRS{reset_method}=="pm" ATTRS{revision}=="0x00" ATTRS{secondary_bus_number}=="8" ATTRS{subordinate_bus_number}=="8" ATTRS{subsystem_device}=="0x1484" ATTRS{subsystem_vendor}=="0x1022" ATTRS{vendor}=="0x1022" looking at parent device '/devices/pci0000:00/0000:00:01.2/0000:02:00.0': KERNELS=="0000:02:00.0" SUBSYSTEMS=="pci" DRIVERS=="pcieport" ATTRS{ari_enabled}=="0" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x060400" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{current_link_speed}=="16.0 GT/s PCIe" ATTRS{current_link_width}=="4" ATTRS{d3cold_allowed}=="1" ATTRS{device}=="0x57ad" ATTRS{dma_mask_bits}=="32" ATTRS{driver_override}=="(null)" ATTRS{enable}=="2" ATTRS{irq}=="24" ATTRS{link/l1_1_aspm}=="0" ATTRS{link/l1_1_pcipm}=="0" ATTRS{link/l1_aspm}=="0" ATTRS{local_cpulist}=="0-23" ATTRS{local_cpus}=="00ffffff" ATTRS{max_link_speed}=="16.0 GT/s PCIe" ATTRS{max_link_width}=="8" ATTRS{msi_bus}=="1" ATTRS{numa_node}=="-1" ATTRS{power/async}=="enabled" ATTRS{power/autosuspend_delay_ms}=="100" ATTRS{power/control}=="auto" ATTRS{power/runtime_active_kids}=="7" ATTRS{power/runtime_active_time}=="7714049" ATTRS{power/runtime_enabled}=="enabled" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="0" ATTRS{power/wakeup}=="disabled" ATTRS{power/wakeup_abort_count}=="" ATTRS{power/wakeup_active}=="" ATTRS{power/wakeup_active_count}=="" ATTRS{power/wakeup_count}=="" ATTRS{power/wakeup_expire_count}=="" ATTRS{power/wakeup_last_time_ms}=="" ATTRS{power/wakeup_max_time_ms}=="" ATTRS{power/wakeup_total_time_ms}=="" ATTRS{power_state}=="D0" ATTRS{reset_method}=="pm bus" ATTRS{revision}=="0x00" ATTRS{secondary_bus_number}=="3" ATTRS{subordinate_bus_number}=="10" ATTRS{subsystem_device}=="0x0000" ATTRS{subsystem_vendor}=="0x0000" ATTRS{vendor}=="0x1022" looking at parent device '/devices/pci0000:00/0000:00:01.2': KERNELS=="0000:00:01.2" SUBSYSTEMS=="pci" DRIVERS=="pcieport" ATTRS{aer_rootport_total_err_cor}=="0" ATTRS{aer_rootport_total_err_fatal}=="0" ATTRS{aer_rootport_total_err_nonfatal}=="0" ATTRS{ari_enabled}=="0" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x060400" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{current_link_speed}=="16.0 GT/s PCIe" ATTRS{current_link_width}=="4" ATTRS{d3cold_allowed}=="1" ATTRS{device}=="0x1483" ATTRS{dma_mask_bits}=="32" ATTRS{driver_override}=="(null)" ATTRS{enable}=="2" ATTRS{irq}=="28" ATTRS{local_cpulist}=="0-23" ATTRS{local_cpus}=="00ffffff" ATTRS{max_link_speed}=="16.0 GT/s PCIe" ATTRS{max_link_width}=="8" ATTRS{msi_bus}=="1" ATTRS{msi_irqs/28}=="msi" ATTRS{numa_node}=="-1" ATTRS{power/async}=="enabled" ATTRS{power/autosuspend_delay_ms}=="100" ATTRS{power/control}=="auto" ATTRS{power/runtime_active_kids}=="1" ATTRS{power/runtime_active_time}=="7714051" ATTRS{power/runtime_enabled}=="enabled" ATTRS{power/runtime_status}=="active" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="0" ATTRS{power/wakeup}=="enabled" ATTRS{power/wakeup_abort_count}=="0" ATTRS{power/wakeup_active}=="0" ATTRS{power/wakeup_active_count}=="0" ATTRS{power/wakeup_count}=="0" ATTRS{power/wakeup_expire_count}=="0" ATTRS{power/wakeup_last_time_ms}=="0" ATTRS{power/wakeup_max_time_ms}=="0" ATTRS{power/wakeup_total_time_ms}=="0" ATTRS{power_state}=="D0" ATTRS{reset_method}=="pm" ATTRS{revision}=="0x00" ATTRS{secondary_bus_number}=="2" ATTRS{subordinate_bus_number}=="10" ATTRS{subsystem_device}=="0x1453" ATTRS{subsystem_vendor}=="0x1022" ATTRS{vendor}=="0x1022" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS=="" ATTRS{power/async}=="enabled" ATTRS{power/control}=="auto" ATTRS{power/runtime_active_kids}=="24" ATTRS{power/runtime_active_time}=="0" ATTRS{power/runtime_enabled}=="disabled" ATTRS{power/runtime_status}=="unsupported" ATTRS{power/runtime_suspended_time}=="0" ATTRS{power/runtime_usage}=="0" ATTRS{waiting_for_supplier}=="0" ```
@luzfcb : your question pertains more to the main NUT repository issue tracker, and probably bring it up (add a link) on the NUT mailing list. This repo is specifically about the DDL (device NUT data dumps library), and the scripts above help collect such data snapshots for comparisons or recordings of activity to simulate later.
I am not well versed in USB programming specifically, but generally I would guess a new driver would be more about determining the vendor protocol used than about the hardware link details the tools above reported in your post.
OTOH, current nutdrv_qx
and usbhid_ups
drivers support trying to use vendorid
+productid
+subdriver
run-time parameters so as to try "lock-picking" devices whose IDs are not yet known and compiled into specific drivers. Earlier seemingly related 0925:1234
IDs are handled by nutdrv_qx
(and older richcomm_usb
).
My first step would be to set up a loop that would try starting the driver programs from command line to dump device information, until something is successful and reasonable, and only investigate vendor protocols or reverse engineering if your device looks like nothing we have coded for earlier.
@jimklimov Thanks for the explanations.
My first step would be to set up a loop that would try starting the driver programs from command line to dump device information, until something is successful and reasonable, and only investigate vendor protocols or reverse engineering if your device looks like nothing we have coded for earlier.
Is there any official or non-official step-by-step documentation on how I can do this process?
Not that I'm aware of, quickly...
Essentially it would be just a loop of shell scripting to iterate subdriver
values (which you can find in the help of your NUT driver programs). Note that usbhid-ups
with this feature is part of NUT v2.8.1 release or current master; most pre-packaged builds are older. But I'd guess that nutdrv_qx
is a more likely fit, and it supports needed options for quite a while.
So the skeleton would be roughly like this, to run with debugging and exit after printing one upsc
-like collection of data (if present):
:; for S in <divinated list of subdriver strings> ; do \
echo "=== $S"; \
nutdrv_qx -s test -x port=auto -x vendorid=0925 -x productid=1241 -x subdriver="$S" -DDDDDD -d1 ; \
done 2>&1 | tee test.log
Which would leave you with a wall of text (and a test.log
file) to review. Maybe you would need some more -x option(=val)
clarifications.
The Megatec Qx family of protocols typically reply with text strings (USB/serial friendly) which start with a parenthesis and follow up with some voltages, temperatures, and a bit-mask of some states, depending on the query. They are quite recognizable and make sense "visually" if you see them in wire captures or NUT driver logs; but then there are many vendor-specific dialects.
USB HID is more formal and binary (and some vendors do botch the encoding). Here probably an explore mode of usbhid-ups
driver can help better with the first step (to rule out non-HID devices), or possibly third-party tools like usbhid-dump
. Note that sometimes useful data may be not on the default (number 0) "interface". Just recently the NUT master codebase got options to tune the numbers involved in USB low-level links, but it is an experimental gray area so far.
The nut, repository and main distribution, provides 2 helper scripts to help in the generation of device dumps:
This should also be documented in the main DDL repository, and in the Developer (and probably also the User) documentations