[Nut-upsdev] help writing a usb hid driver for existing ups

Libor Klepáč libor.klepac at bcom.cz
Tue Jan 22 13:27:56 UTC 2008


Hi there,

I think, I have also this type of device (Powercom Blacknight 800VA), I was 
sending some dumps of communication from windows, one year ago. Unfortunately 
i'm not programer, but i can help testing if needed.

Cu
Libor

On Tuesday 22 January 2008 01:53:04 pm Michael Tokarev wrote:
> Charles Lepple wrote:
> > Hi Michael,
> >
> > On Jan 21, 2008 7:59 AM, Michael Tokarev <mjt at tls.msk.ru> wrote:
> >> 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).
> >
> > It sounds like you may want to talk with Alexey Sidirov to coordinate
> > support for this device.
>
> Yeah, I tried to reach him - to no avail so far... ;)
> [Update: he replied, telling he has urgent work to do before
> he will be able to work with all this stuff again]
>
> > Can you post the output of 'lsusb -vvv' (run as root) for this device?
> > (You will get a little more information from lsusb if you run
> > 'usbhid-ups' once with the "-x explore" option, although usbhid-ups
> > will probably not tell us much since they seem to not follow the USB
> > Power Device Class (PDC) HID protocol.)
>
> Here it is:
>
> # usbhid-ups -DDD -a hid -u root -x explore -x vendorid=0d9f -x
> productid=0002 Network UPS Tools: 0.29 USB communication driver - core 0.32
> (2.2.1)
>
> debug level is '3'
> upsdrv_initups...
> Checking device (0D9F/0002) (002/004)
> - VendorID: 0d9f
> - ProductID: 0002
> - Manufacturer: POWERCOM CO., LTD.
> - Product: USB to Serial
> - Serial Number: unknown
> - Bus: 002
> Trying to match device
> Device matches
> failed to claim USB device, trying 2 more time(s)...
> detaching kernel driver from USB device...
> trying again to claim USB device...
> HID descriptor, method 1: (9 bytes) => 09 21 00 01 00 01 22 25 00
> HID descriptor, method 2: (9 bytes) => 09 21 00 01 00 01 22 25 00
> HID descriptor length 37
> Report Descriptor size = 37
> Report Descriptor: (37 bytes) => 06 a0 ff 09 01 a1 01 09 01 15 00 26 ff 00
> 75 08 95 08 81 02 09 02 75 08 95 08 91 02 09 03 75 08 95 05 b1 02 c0
> Using subdriver: EXPLORE HID 0.1
> Report[get]: (2 bytes) => 00 00
> Path: ffa00001.ffa00001, Type: Input, ReportID: 0x00, Offset: 0, Size: 8,
> Value: 0.000000 Report[buf]: (2 bytes) => 00 00
> Path: ffa00001.ffa00002, Type: Output, ReportID: 0x00, Offset: 0, Size: 8,
> Value: 0.000000 Report[buf]: (2 bytes) => 00 00
> Path: ffa00001.ffa00003, Type: Feature, ReportID: 0x00, Offset: 0, Size: 8,
> Value: 0.000000 Report descriptor retrieved (Reportlen = 37)
> Found HID device
> Detected a UPS: POWERCOM CO., LTD./USB to Serial
> ^C
>
>
> # lsusb -vvv
> Bus 002 Device 004: ID 0d9f:0002 Powercom Co., Ltd
> Device Descriptor:
>   bLength                18
>   bDescriptorType         1
>   bcdUSB               1.00
>   bDeviceClass            0 (Defined at Interface level)
>   bDeviceSubClass         0
>   bDeviceProtocol         0
>   bMaxPacketSize0         8
>   idVendor           0x0d9f Powercom Co., Ltd
>   idProduct          0x0002
>   bcdDevice            0.00
>   iManufacturer           1 POWERCOM CO., LTD.
>   iProduct                2 USB to Serial
>   iSerial                 0
>   bNumConfigurations      1
>   Configuration Descriptor:
>     bLength                 9
>     bDescriptorType         2
>     wTotalLength           41
>     bNumInterfaces          1
>     bConfigurationValue     1
>     iConfiguration          4 Sample HID
>     bmAttributes         0x80
>       (Bus Powered)
>     MaxPower              100mA
>     Interface Descriptor:
>       bLength                 9
>       bDescriptorType         4
>       bInterfaceNumber        0
>       bAlternateSetting       0
>       bNumEndpoints           2
>       bInterfaceClass         3 Human Interface Device
>       bInterfaceSubClass      0 No Subclass
>       bInterfaceProtocol      0 None
>       iInterface              0
>         HID Device Descriptor:
>           bLength                 9
>           bDescriptorType        33
>           bcdHID               1.00
>           bCountryCode            0 Not supported
>           bNumDescriptors         1
>           bDescriptorType        34 Report
>           wDescriptorLength      37
>           Report Descriptor: (length is 37)
>             Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
>                             (null)
>             Item(Local ): Usage, data= [ 0x01 ] 1
>                             (null)
>             Item(Main  ): Collection, data= [ 0x01 ] 1
>                             Application
>             Item(Local ): Usage, data= [ 0x01 ] 1
>                             (null)
>             Item(Global): Logical Minimum, data= [ 0x00 ] 0
>             Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
>             Item(Global): Report Size, data= [ 0x08 ] 8
>             Item(Global): Report Count, data= [ 0x08 ] 8
>             Item(Main  ): Input, data= [ 0x02 ] 2
>                             Data Variable Absolute No_Wrap Linear
>                             Preferred_State No_Null_Position Non_Volatile
> Bitfield Item(Local ): Usage, data= [ 0x02 ] 2
>                             (null)
>             Item(Global): Report Size, data= [ 0x08 ] 8
>             Item(Global): Report Count, data= [ 0x08 ] 8
>             Item(Main  ): Output, data= [ 0x02 ] 2
>                             Data Variable Absolute No_Wrap Linear
>                             Preferred_State No_Null_Position Non_Volatile
> Bitfield Item(Local ): Usage, data= [ 0x03 ] 3
>                             (null)
>             Item(Global): Report Size, data= [ 0x08 ] 8
>             Item(Global): Report Count, data= [ 0x05 ] 5
>             Item(Main  ): Feature, data= [ 0x02 ] 2
>                             Data Variable Absolute No_Wrap Linear
>                             Preferred_State No_Null_Position Non_Volatile
> Bitfield Item(Main  ): End Collection, data=none
>       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              10
>       Endpoint Descriptor:
>         bLength                 7
>         bDescriptorType         5
>         bEndpointAddress     0x02  EP 2 OUT
>         bmAttributes            3
>           Transfer Type            Interrupt
>           Synch Type               None
>           Usage Type               Data
>         wMaxPacketSize     0x0008  1x 8 bytes
>         bInterval              10
> Device Status:     0x0000
>   (Bus Powered)
>
> > Since it is the same protocol as the serial powercom driver, you can
>
> Well, I hope it is.  But looking at the strings read from the
> device by their program (upsmon) more closely, I'm not very
> sure anymore.  I asked their support, maybe I'll have some
> more info on this.
>
> > use the same technique as in the megatec and megatec_usb code: link
> > the core powercom code with the serial functions for the regular
> > powercom driver, and with USB HID code in powercom_usb.c (for
> > instance).
> >
> > There are two ways to write the USB interface code. One is to use
> > libusb functions, which are portable to other OSes like FreeBSD,
> > NetBSD, OS X, and potentially Solaris. The other way (not recommended,
> > but may be easier) is to just use the ioctl() calls that you found
> > from strace.
> >
> > The first method is used by megatec_usb and usbhid-ups. The second
> > method is used by energizerups.
>
> Ok, I'll try to explore those.  The thing is that I don't know a bit
> about the whole USB thing, and don't have intention to learn it at
> full, either... ;)
>
> By the way, there's a kernel-level usbserial kernel-level driver
> for this device, written by another guy in Russia (I think I
> mentioned that before), -- with that driver and powercom.c
> from nut the device works.  So I wonder if it will be simpler
> to write a user-level serial driver and embed it into
> powercom.c module, instead of fidding with hid.  Either
> way, it's still black magic for me ;)
>
> >> 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
> >
> > You will have to do a little reverse engineering here to figure out
> > which fields are being passed in, and what they mean. I think that
> > report_type, report_id and usage_code are passed in, and the others
> > are returned by this ioctl() call.
>
> Note I patched strace(1) utility to print the info here.  Before,
> it just printed `ioctl(3, HIDIOCGUSAGE, 0x123456789)' - ie, an
> address of the structure.  I looked the ioctl in the linux kernel
> headers and added some code into strace to show the argument.
>
> But again, since I don't know anything about USB and how it works
> internally, the structure fields is of no great use to me... ;)
>
> >> 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
> >
> > This is most likely an interrupt read over whatever the input pipe is.
>
> Funny thing is that the data is available almost immediately - the
> select() call never sleeps for too much.  It looks like the device
> is constantly feeding something to the host.  UNLIKE the "pure"
> serial protocol.
>
> >> Here's the init stuff:
>
> []
>
> >> 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
> >
> > Not sure exactly what's going on here, but it looks like they are
> > writing to the device (In HIDIOC + S + USAGE/REPORT, the 'S' is for
> > "set", and 'G' stands for "get").
>
> Heh.  I figured it out that G vs S thing.. ;)  What I need is
> someone who knows what it all does, and who's willing to help
> a bit to get me started... ;)  I hope anyway :)
>
> Thanks!
>
> /mjt
>
> _______________________________________________
> Nut-upsdev mailing list
> Nut-upsdev at lists.alioth.debian.org
> http://lists.alioth.debian.org/mailman/listinfo/nut-upsdev


-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
Url : http://lists.alioth.debian.org/pipermail/nut-upsdev/attachments/20080122/36802390/attachment.pgp 


More information about the Nut-upsdev mailing list