[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