[Nut-upsdev] help writing a usb hid driver for existing ups
Michael Tokarev
mjt at tls.msk.ru
Mon Jan 21 12:59:44 UTC 2008
I've got a Powercom Imperial UPS, with an internal
USB<=>serial converter. It implements the same
protocol as other powercom devices implements, but
only when talking over serial port (there's no such
port on the device). Someone wrote a draft version
of usbserial driver for it, and the UPS works with
this kernel-level driver and with powercom driver
from nut (using /dev/ttyUSBx device).
The UPS comes with OEM program, upsmon, that talks
to the device using /dev/hiddevX device node, i.e.
using USB HID protocol. I captured some (s)traces
of it when at work(*).
The question is how to write proper driver for it
(because using kernel-mode usbserial driver looks
a bit.. too much and ugly). I don't understand
how USB and HID works.
(megatec_usb doesn't work with it - the serial
protocol is different).
What's the place to start with all this stuff,
having in mind that I don't want to learn all
the HID stuff - just some basics (probably just
an example) necessary to implement the driver.
(*) their program is looping doing the following
at regular intervals:
654 time(NULL) = 1200921228
654 ioctl(3, HIDIOCGUSAGE, {report_type=1, report_id=0, field_index=0, usage_index=0, usage_code=ffa00001, value=240}) = 0
654 select(4, [3], NULL, NULL, {3, 0}) = 1 (in [3], left {2, 990000})
654 read(3, "\1\0\240\377\360\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0", 512) = 64
654 time(NULL) = 1200921228
654 ioctl(3, HIDIOCGUSAGE, {report_type=1, report_id=0, field_index=0, usage_index=0, usage_code=ffa00001, value=240}) = 0
654 select(4, [3], NULL, NULL, {3, 0}) = 1 (in [3], left {2, 990000})
654 read(3, "\1\0\240\377\360\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0\1\0\240\377\0\0\0\0", 512) = 64
654 time(NULL) = 1200921228
...
with some init stuff before (fd#3 is /dev/hiddev0).
What it reads looks pretty much the same as the stuff
returned by similar UPS connected over normal serial
port (but 4x more - there are 4 identical blocks of
data read, each of 16bytes in size).
Here's the init stuff:
653 open("/dev/hiddev0", O_RDONLY) = 3
653 ioctl(3, HIDIOCAPPLICATION, 0) = -6291455
653 ioctl(3, HIDIOCAPPLICATION, 0) = -6291455
653 ioctl(3, HIDIOCGVERSION, 0xbfb09fdc) = 0
653 write(1, "hiddev driver version is 1.0.4\n", 31) = 31
653 ioctl(3, HIDIOCGDEVINFO, 0xbfb0a480) = 0
653 ioctl(3, HIDIOCAPPLICATION, 0) = -6291455
653 write(1, "HID: vendor 0xd9f product 0x2 version 0x0 applications [1]: ffa00001\n", 69) = 69
653 write(1, "HID: bus: 2 devnum: 4 ifnum: 0\n", 31) = 31
653 ioctl(3, 0x81004806, 0xbfb0a380) = 33
653 write(1, "UPS HID device name: \"POWERCOM CO., LTD. USB to Serial\"\n", 56) = 56
653 ioctl(3, HIDIOCINITREPORT, 0) = 0
653 ioctl(3, HIDIOCGUSAGE, {report_type=3, report_id=ffffffff, field_index=0, usage_index=0, usage_code=850089, value=0}) = -1 EINVAL (Invalid argument)
653 ioctl(3, HIDIOCGUSAGE, {report_type=3, report_id=ffffffff, field_index=0, usage_index=0, usage_code=8400ff, value=0}) = -1 EINVAL (Invalid argument)
653 ioctl(3, HIDIOCSUSAGE, {report_type=3, report_id=0, field_index=0, usage_index=0, usage_code=ffa00003, value=95}) = 0
653 ioctl(3, HIDIOCSREPORT, {report_type=3,report_id=0,num_fields=0}) = 0
653 ioctl(3, HIDIOCSUSAGE, {report_type=3, report_id=0, field_index=0, usage_index=1, usage_code=ffa00003, value=4}) = 0
653 ioctl(3, HIDIOCSREPORT, {report_type=3,report_id=0,num_fields=0}) = 0
653 ioctl(3, HIDIOCSUSAGE, {report_type=3, report_id=0, field_index=0, usage_index=2, usage_code=ffa00003, value=0}) = 0
653 ioctl(3, HIDIOCSREPORT, {report_type=3,report_id=0,num_fields=0}) = 0
653 ioctl(3, HIDIOCSUSAGE, {report_type=3, report_id=0, field_index=0, usage_index=3, usage_code=ffa00003, value=0}) = 0
653 ioctl(3, HIDIOCSREPORT, {report_type=3,report_id=0,num_fields=0}) = 0
653 ioctl(3, HIDIOCSUSAGE, {report_type=3, report_id=0, field_index=0, usage_index=4, usage_code=ffa00003, value=3}) = 0
653 ioctl(3, HIDIOCSREPORT, {report_type=3,report_id=0,num_fields=0}) = 0
653 ioctl(3, HIDIOCSUSAGE, {report_type=2, report_id=0, field_index=0, usage_index=0, usage_code=ffa00002, value=1}) = 0
653 ioctl(3, HIDIOCSUSAGE, {report_type=2, report_id=0, field_index=0, usage_index=1, usage_code=ffa00002, value=1}) = 0
653 ioctl(3, HIDIOCSREPORT, {report_type=2,report_id=0,num_fields=0}) = 0
As I stated above, I don't know anything about all
this HID stuff and how it works, even the basic
principles...
Thanks!
/mjt
More information about the Nut-upsdev
mailing list