[libhid-discuss] Trying to repair a program using libhid to configure an Ultimarc Joystick

Andrew Silverman andrewsi at microsoft.com
Wed Mar 25 03:10:15 UTC 2015


Hi folks - question from newbie.

There is a piece of software that was written several years ago to allow Linux users to configure a USB joystick from Ultimarc.  The company has Windows specific tools but no formal support for Linux.
The tool relies on libhid and the libusb-compat libraries.  A recent firmware change for this joystick seems to have broken the current version of the Linux configuration tool and I am trying to get some help modifying it to work with this latest FW update.

The joystick is VID/PID d209:0511.  It exposes three separate endpoints, EP 2 IN (0x82) which is the two-axis joystick, EP 1 IN which allows the joystick to sometimes behave as a mouse, and then there is EP 3 IN (0x83) which is evidently the endpoint that needs to be written to in order to configure the stick.

The present version of the application is successful at finding and force_opening the device, but I have a suspicion that it may not be writing to the correct endpoint with this latest firmware release.  The stick manufacturer confirms that they used to use libusb under Windows, but with this latest release they use native Windows functionality to write to the HID device.  They also confirm that EP3 is where the data's supposed to go.  However, they haven't been entirely forthcoming with complete documentation of the vendor-specific protocol, but they claim no changes have been made in the actual data that needs to be transmitted to the device.

The existing version of the utility seems to rely on making calls to usb_control_msg() to actually send the data, but the behavior I see now with the latest firmware is that the line I've marked below with an arrow always fails with EPIPE, saying that the endpoint is stalled.  (I added some debug prints to my copy of the code to inspect the return values, which the original author was ignoring.)  Unfortunately I'm a little new to USB programming (at least at this level of detail) and am having a little difficulty in translating the calls the original author of the application (now unresponsive) is making into the commands in the USB spec, and therefore, what I would need to change in order to make a hopefully simple change to direct the traffic to endpoint EP 3, (if indeed that is the problem.)

I've included a snippet of the app below, please let me know if there's something reasonably obvious I can change to ensure that the data goes to the correct endpoint, or whether there is potentially some other avenue of investigation I should be looking at.  I can always email the entire single source file (it's not very long) if you need to see more, but I think this is really the relevant piece.  I don't want to rewrite the whole app, I just want to get it basically functional again.  Thanks for any/all help!

// *********************Send Map Transfer*******************************
                                // This is only for Map Size = 9
                                //
                                // 3 "Data Write" Transfers of 32 Bytes
                                // -First Transfer-
                                // Byte[0] = 0x50 (Header)
                                // Byte[1] = 0x09 (Map Size?)
                                // Byte[2] = Restrictor (RestrictorOn = 0x09, RestrictorOff = 0x10)
                                // Byte[3]-Byte[10] = Map Border Location
                                // Byte[11]-Byte[31] = Mapping of Block Location. starting from topleft and read left to right.
                                //
                                // -Second Transfer-
                                // 32 Bytes - Continue Mapping of Block Location
                                //
                                // -Third Transfer-
                                // Byte[0]-Byte[27] - Continue Mapping of Block Location
                                // Byte[28]-Byte[30] - 0x00
                                // Byte[31] - (Write to Flash 0x00) (Write to RAM 0xFF, supported in Firmware 2.2)
                                //
                                //
                                // ****************************************************
                                // USB      Mapping
                                // 0x00 =   Analog (-)
                                // 0x01 =   Center (C)
                                // 0x02 =   Up (N)
                                // 0x03 =   UPRight (NE)
                                // 0x04 =   Right (E)
                                // 0x05 =   DownRight (SE)
                                // 0x06 =   Down (S)
                                // 0x07 =   DownLeft (SW)
                                // 0x08 =   Left (W)
                                // 0x09 =   UPLeft (NW)
                                // 0x0A =   Sticky (*)

                                // MapFileFormatVersion=1.0

                                // MapSize=9
                                // MapBorderLocations=30,58,86,114,142,170,198,226
                                // MapRow1=W,W,W,C,C,C,E,E,E
                                // MapRow2=W,W,W,C,C,C,E,E,E
                                // MapRow3=W,W,W,C,C,C,E,E,E
                                // MapRow4=W,W,W,C,C,C,E,E,E
                                // MapRow5=W,W,W,C,C,C,E,E,E
                                // MapRow6=W,W,W,C,C,C,E,E,E
                                // MapRow7=W,W,W,C,C,C,E,E,E
                                // MapRow8=W,W,W,C,C,C,E,E,E
                                // MapRow9=W,W,W,C,C,C,E,E,E

                                if(arguments.rowcount == 9){

                                                int usbret = usb_control_msg(hid->dev_handle,0x43,0xE9,0x0001, 0 , NULL, 0,1000);
                                                char data[32*3]; // 9*9 + 3 + 8 + 1 round up to nearest 32 block.
                                                memset(data,0,sizeof(data));

                                                data[0]  = 0x50; // Byte[0] = 0x50 (Header)
                                                data[1]  = 0x09; // Byte[1] = 0x09 (Map Size?)
                                                data[2] = ( arguments.restrictor ? 0x09 : 0x10 ); // Byte[2] = Restrictor (RestrictorOn = 0x09, RestrictorOff = 0x10)
                                                data[95] = ( arguments.flash ? 0x00 : 0xFF ); // Byte[31] - (Write to Flash 0x00) (Write to RAM 0xFF, supported in Firmware 2.2)

                                                if(arguments.border_set){
                                                                // Byte[3]-Byte[10] = Map Border Location
                                                                memcpy(&data[3],arguments.border,sizeof(arguments.border));
                                                }

                                                memcpy(&data[11],arguments.matrix,9*9);

                                                for(int i=0;i<3;i++){
                                                                usbret = usb_control_msg(hid->dev_handle,0x43,0xEB,0x0000, 0 , data+(32*i), sizeof(data)/3,1000);

This fails---------------->                  usbret = usb_control_msg(hid->dev_handle,0xC3,0xEA,0x0000, 0 , NULL, 0 ,1000);

                                                }

                                                usbret = usb_control_msg(hid->dev_handle,0x43,0xE9,0x0000, 0 , NULL, 0,1000);
                                }
                }
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20150325/8bb00483/attachment-0001.html>


More information about the libhid-discuss mailing list