C [usbhid] Accessing multiple joysticks in one report

Hello dear FreeBSD community.
I'm trying to access a joystick (or better said two) through usbhid(3)
However, when using hid_start_parse (desc, 1, 2) I can't only receive the item with the 2nd report ID (I also get the data from the Item with the Report ID 1). So I wanted to ask if I'm doing something wrong or if it's usbhid(3) which doesn't allow me access. The joysticks are located at /dev/uhid1, (they share one node) that's why it's hardcoded.

My descriptor goes as following:
Code:
0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
0x09, 0x04,  // Usage (Joystick)
0xA1, 0x01,  // Collection (Application)
0x85, 0x01,  //  Report ID (1)
0xA1, 0x02,  //  Collection (Logical)
0x75, 0x08,  //  Report Size (8)
0x95, 0x04,  //  Report Count (4)
0x15, 0x00,  //  Logical Minimum (0)
0x26, 0xFF, 0x00,  //  Logical Maximum (255)
0x35, 0x00,  //  Physical Minimum (0)
0x46, 0xFF, 0x00,  //  Physical Maximum (255)
0x09, 0x32,  //  Usage (Z)
0x09, 0x35,  //  Usage (Rz)
0x09, 0x30,  //  Usage (X)
0x09, 0x31,  //  Usage (Y)
0x81, 0x02,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x04,  //  Report Size (4)
0x95, 0x01,  //  Report Count (1)
0x25, 0x07,  //  Logical Maximum (7)
0x46, 0x3B, 0x01,  //  Physical Maximum (315)
0x65, 0x14,  //  Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39,  //  Usage (Hat switch)
0x81, 0x42,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00,  //  Unit (None)
0x75, 0x01,  //  Report Size (1)
0x95, 0x0C,  //  Report Count (12)
0x25, 0x01,  //  Logical Maximum (1)
0x45, 0x01,  //  Physical Maximum (1)
0x05, 0x09,  //  Usage Page (Button)
0x19, 0x01,  //  Usage Minimum (0x01)
0x29, 0x0C,  //  Usage Maximum (0x0C)
0x81, 0x02,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF,  //  Usage Page (Vendor Defined 0xFF00)
0x75, 0x01,  //  Report Size (1)
0x95, 0x08,  //  Report Count (8)
0x25, 0x01,  //  Logical Maximum (1)
0x45, 0x01,  //  Physical Maximum (1)
0x09, 0x01,  //  Usage (0x01)
0x81, 0x02,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,  //  End Collection
0xA1, 0x02,  //  Collection (Logical)
0x75, 0x08,  //  Report Size (8)
0x95, 0x04,  //  Report Count (4)
0x46, 0xFF, 0x00,  //  Physical Maximum (255)
0x26, 0xFF, 0x00,  //  Logical Maximum (255)
0x09, 0x02,  //  Usage (0x02)
0x91, 0x02,  //  Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,  //  End Collection
0xC0,  // End Collection
0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
0x09, 0x04,  // Usage (Joystick)
0xA1, 0x01,  // Collection (Application)
0x85, 0x02,  //  Report ID (2)
0xA1, 0x02,  //  Collection (Logical)
0x75, 0x08,  //  Report Size (8)
0x95, 0x04,  //  Report Count (4)
0x15, 0x00,  //  Logical Minimum (0)
0x26, 0xFF, 0x00,  //  Logical Maximum (255)
0x35, 0x00,  //  Physical Minimum (0)
0x46, 0xFF, 0x00,  //  Physical Maximum (255)
0x09, 0x32,  //  Usage (Z)
0x09, 0x35,  //  Usage (Rz)
0x09, 0x30,  //  Usage (X)
0x09, 0x31,  //  Usage (Y)
0x81, 0x02,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x04,  //  Report Size (4)
0x95, 0x01,  //  Report Count (1)
0x25, 0x07,  //  Logical Maximum (7)
0x46, 0x3B, 0x01,  //  Physical Maximum (315)
0x65, 0x14,  //  Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39,  //  Usage (Hat switch)
0x81, 0x42,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00,  //  Unit (None)
0x75, 0x01,  //  Report Size (1)
0x95, 0x0C,  //  Report Count (12)
0x25, 0x01,  //  Logical Maximum (1)
0x45, 0x01,  //  Physical Maximum (1)
0x05, 0x09,  //  Usage Page (Button)
0x19, 0x01,  //  Usage Minimum (0x01)
0x29, 0x0C,  //  Usage Maximum (0x0C)
0x81, 0x02,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF,  //  Usage Page (Vendor Defined 0xFF00)
0x75, 0x01,  //  Report Size (1)
0x95, 0x08,  //  Report Count (8)
0x25, 0x01,  //  Logical Maximum (1)
0x45, 0x01,  //  Physical Maximum (1)
0x09, 0x01,  //  Usage (0x01)
0x81, 0x02,  //  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,  //  End Collection
0xA1, 0x02,  //  Collection (Logical)
0x75, 0x08,  //  Report Size (8)
0x95, 0x04,  //  Report Count (4)
0x46, 0xFF, 0x00,  //  Physical Maximum (255)
0x26, 0xFF, 0x00,  //  Logical Maximum (255)
0x09, 0x02,  //  Usage (0x02)
0x91, 0x02,  //  Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,  //  End Collection
0xC0,  // End Collection

// 202 bytes, generated by http://eleccelerator.com/usbdescreqparser/

Here is my code which is partially based on the BSD driver for SDL (which isn't working properly either):
Code:
#include <iostream>
#include <usbhid.h>
#include <dev/usb/usbhid.h>
#include <fcntl.h>

using namespace std;

/*
#define HUP_GENERIC_DESKTOP  0x0001
#define HUG_JOYSTICK  0x0004
#define HUG_GAME_PAD  0x0005
#define HUP_BUTTON  0x0009
*/

enum
{
  JOYAXE_X,
  JOYAXE_Y,
  JOYAXE_Z,
  JOYAXE_SLIDER,
  JOYAXE_WHEEL,
  JOYAXE_RX,
  JOYAXE_RY,
  JOYAXE_RZ,
  JOYAXE_count
};


static int
usage_to_joyaxe(unsigned usage)
{
  int joyaxe;
  switch (usage) {
  case HUG_X:
  joyaxe = JOYAXE_X;
  break;
  case HUG_Y:
  joyaxe = JOYAXE_Y;
  break;
  case HUG_Z:
  joyaxe = JOYAXE_Z;
  break;
  case HUG_SLIDER:
  joyaxe = JOYAXE_SLIDER;
  break;
  case HUG_WHEEL:
  joyaxe = JOYAXE_WHEEL;
  break;
  case HUG_RX:
  joyaxe = JOYAXE_RX;
  break;
  case HUG_RY:
  joyaxe = JOYAXE_RY;
  break;
  case HUG_RZ:
  joyaxe = JOYAXE_RZ;
  break;
  default:
  joyaxe = -1;
  }
  return joyaxe;
}

void* buffer;
int main()
{
  int id = 0;
  /* Read the default USB HID usage table. */
  //buffer = new void;
  hid_init(NULL);
  int fd;
  report_desc_t desc;
  hid_data_t hdata;
  hid_item_t hitem;
  int v;
  //struct joystick gameport;

  char *path = {"/dev/uhid1"};

  fd = open(path, O_RDONLY);

  if (fd == -1)
  {
  cout << "Failed to open device, check permission\n";
  }
  //cout << hid_get_report_id (fd);
  id = hid_get_report_id (fd);
  desc = hid_get_report_desc(fd);
  int report_size = hid_report_size(desc,hid_input, id);
  buffer = malloc(report_size);
  hdata = hid_start_parse(desc, 1, id ); // 0 Input 1 Output 2 Feature
  int troll = hid_collection;
  while (hid_get_item(hdata, &hitem) > 0)
  {
  char *sp;
  const char *s;
  int test = HID_PAGE(hitem.usage);
  // cout << hitem.kind << endl;
  switch (hitem.kind) {
  case hid_collection:
  switch (HID_PAGE(hitem.usage))
  {
  case HUG_JOYSTICK:
  case HUG_GAME_PAD:
  s  = hid_usage_in_page(hitem.usage);
  cout << "s is:" << s;
  }
  break;
  case hid_input:
  switch (HID_PAGE(hitem.usage))
  {
  case HUP_GENERIC_DESKTOP:
  {
  unsigned usage = HID_USAGE(hitem.usage);
  cout << "Usage found: " << usage << endl;
  }
  break;
  case HUP_BUTTON:
  {
  cout << "Button found" << endl;
  }
  break;
  default:
  break;

  }
  break;
  default: break;
  }
  }
  hid_end_parse(hdata);

  while (read(fd, buffer, report_size) == report_size)//Read the block device into buffer, If a new complete report is available
  {
  hdata = hid_start_parse(desc, 1, 2 ); // 0 Input 1 Output 2 Feature, Start parsing the descriptor
  //id = hid_get_report_id (fd);
  //cout << "ID is:" << id << endl;
  //  int joyNum = 0;
  if (hdata == NULL) {
  /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
  continue;
  }

  while (hid_get_item(hdata, &hitem) > 0) {//As soon as there are any items left
  int nbutton = 0;
  switch (hitem.kind) {//Get the kind of the item
  case hid_input://If it is an Input device
  switch (HID_PAGE(hitem.usage)) {//Check what it' good for
  case HUP_GENERIC_DESKTOP://If it is meant for use at the desktop / If the page is Desktop
  {
  unsigned usage = HID_USAGE(hitem.usage);
  int joyaxe = usage_to_joyaxe(usage); //Map it's usage towards the struct defined in joyaxe
  if (joyaxe >= 0) {//If it matches any axe

//  naxe = joy->hwdata->axis_map[joyaxe];//Set naxe to the current axis
  /* scaleaxe */
  v = hid_get_data(buffer, &hitem); //Get the data
  v -= (hitem.logical_maximum +  //Get the maximum and minimum reported by the descriptor
  hitem.logical_minimum + 1) / 2; // And match the scale for use in SDL
  v *= 32768 /((hitem.logical_maximum - hitem.logical_minimum + 1) / 2);

  cout << "Joy: " << hitem.report_ID << " Axis: " << joyaxe << " Value: " << v << endl;
  //  if (v != joy->axes[naxe]) {
  //  SDL_PrivateJoystickAxis(joy, naxe, v);
  //  }
  } else if (usage == HUG_HAT_SWITCH) {  // If it is a HAT_SWITCH
//  v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem); // Get the data
//  SDL_PrivateJoystickHat(joy, 0,  // Match the HAT value reported to SDL
//  hatval_to_sdl(v) -
//  hitem.logical_minimum);
  }
  break;
  }
  case HUP_BUTTON://If it's a Button
  v = hid_get_data(buffer, &hitem);//Get the data from it
  //if (joy->buttons[nbutton] != v) {//If state changed
//  SDL_PrivateJoystickButton(joy, nbutton, v);
  //}
  // cout << "Button: " << nbutton << " pressed:" << v << endl; //and print it out
  nbutton++;//Iterate through nbutton
  break;
  default:
  continue;
  }
  break;
  default:
  break;
  }
  }
  hid_end_parse(hdata);
  }

  cout << "Ending" << endl;
  cin.ignore();
  return 0;
}

It would always output both reports. Even when printing report_ID (from the item) together with the axis value. report_ID would remain constant while it outputs the value from two different items (which should also have different report_IDs). I am quite inexperienced in matters of developing so please forgive me my non-professionalism.
EDIT:
I have a workaround for this, after having parsed one report, I simply toggle the joystick number. But maybe there is a better solution out there.
 
Back
Top