Source file: /~heha/hs/bl/hid-flash.zip/src/hid-hidraw.cpp

/* HIDAPI - Multi-Platform library for communication with HID devices.
 8/22/2009	Alan Ott, Signal 11 Software
 Hidraw-Version
*/

#include "hidapi.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/hidraw.h>

static byte parseget(const byte*&desc,int&param) {
 byte r=*desc++;
 switch (r&3) {	// encodes number of following bytes
  case 1: param=*desc++; break;
  case 2: param=*(*reinterpret_cast<const int16_t**>(&desc))++; break;
  case 3: param=*(*reinterpret_cast<const int32_t**>(&desc))++; break;
  default: param=0;
 }
 return r;
}

static bool hidparse(const byte*desc,unsigned len,hid::Caps&caps) {
 int globalitems[16],localitems[16];
 memset(&caps,0,sizeof caps);
 auto end=desc+len;
 while (desc<end) {
  int param;
  byte r=parseget(desc,param);
//fprintf(stderr," %02X(%d)",r,param);
  switch (r&0x0C) {
   case 0x04: globalitems[r>>4]=param; break;
   case 0x08: localitems[r>>4]=param; break;
   case 0x00: {
    int rsize=globalitems[7],rid=globalitems[8],rcount=globalitems[9];
    if (rcount>1) rsize = (rsize+7)&~7;	// byte-align!
    rsize*=rcount;
    switch (r&0xF0) {
     case 0x80: caps.InputReportByteLength+=rsize; break;
     case 0x90: caps.OutputReportByteLength+=rsize; break;
     case 0xB0: caps.FeatureReportByteLength+=rsize; break;
    }
   }break;
  }
 }
 auto adjust = [](int&x) {if (x) x = (x+15)>>3;};
 adjust(caps.OutputReportByteLength);
 adjust(caps.InputReportByteLength);
 adjust(caps.FeatureReportByteLength);
 return true;
}

HidDev::HidDev():handle(0) {}

bool HidDev::connect(unsigned n) {
 ++n;
 for (unsigned i=0;;i++) {
  char name[32];
  snprintf(name,sizeof name,"/dev/hidraw%u",i);
  int h=open(name,O_RDWR/*|O_NONBLOCK*/);
  if (h<0) break;
  hidraw_devinfo di;
  ioctl(h,HIDIOCGRAWINFO,&di);
  attr.VendorID=di.vendor;
  attr.ProductID=di.product;
  attr.VersionNumber=0;	// Not available using hidraw
  handle=h;
  if (match() && !--n) {
   hidraw_report_descriptor rd;
   ioctl(h,HIDIOCGRDESCSIZE,&rd.size);
   ioctl(h,HIDIOCGRDESC,&rd);
   hidparse(rd.value,rd.size,caps);
//fprintf(stderr,"in=%u,out=%u,feat=%u",
//	caps.InputReportByteLength,
//	caps.OutputReportByteLength,
//	caps.FeatureReportByteLength);
   break;
  }else{
   close(h);
   handle=0;
  }
 }
 return operator bool();
}

HidDev::~HidDev() {
 if (handle) close(handle);
}

bool HidDev::setOutputReport(const byte*data, unsigned attempts, unsigned ms) {
 byte report_number = *data;
 int len=caps.OutputReportByteLength;
// if (!report_number) ++data,--len;
 do{
  if (write(handle,data,len)>=0) return true;
 }while(--attempts);
 return false;
}

bool HidDev::getInputReport(byte*data, unsigned attempts, unsigned ms) {
 byte report_number=*data;
 int len=caps.InputReportByteLength;
 if (!report_number) ++data,--len;
 do{
  if (read(handle,data,len)>=0) return true;	// try interrupt pipe first
 }while(--attempts);
 return false;
}

bool HidDev::setFeatureReport(const byte*data, unsigned attempts) {
 byte report_number = *data;
 int len=caps.FeatureReportByteLength;
// if (!report_number) ++data,--len;
 do{
  if (ioctl(handle,HIDIOCSFEATURE(len),data)>=0) return true;
  retry_msg();
 }while(--attempts);
 return false;
}

bool HidDev::getFeatureReport(byte*data, unsigned attempts) {
 byte report_number = *data;
 int len=caps.FeatureReportByteLength;
// if (!report_number) ++data,--len;
 do{
  if (ioctl(handle,HIDIOCGFEATURE(len),data)>=0) return true;
  retry_msg();
 }while(--attempts);
 return false;
}

HidDev::RetStr HidDev::getIndexedStr(byte idx) const{
 return {0};
}

HidDev::RetStr  HidDev::getManufacturerStr() const{
 RetStr r;	// will be optimized-out
 if (ioctl(handle,HIDIOCGRAWNAME(256),&r.s)<0) r.s[0]=0;
 return r;
}

HidDev::RetStr  HidDev::getProductStr() const{
 return {0};
}

HidDev::RetStr  HidDev::getSerialStr() const{
 return {0};
}

uint32_t HidDev::vidpid() const{
 return *reinterpret_cast<const uint32_t*>(&attr);
}
Detected encoding: ASCII (7 bit)2