Source file: /~heha/basteln/PC/USB2LPT/PortTalk.zip/src/PortTalk.cpp

#include <windows.h>
#include <winioctl.h>
#include <shlwapi.h>
#include <setupapi.h>
extern "C"{
#include <hidsdi.h>
#include <hidpi.h>
}
#define T(x) TEXT(x)

// Opens the n'th (zero-based) HID device that has VID=16C0, PID=06B3 (h#s USB2LPT)
// Use CloseHandle() to free the handle returned.
// Returns 0 when failing.
static HANDLE OpenUsbHid(int n) {
 HANDLE h=0;
 DWORD i;
 HDEVINFO devs;
 GUID hidGuid;		// GUID for HID driver

 HidD_GetHidGuid(&hidGuid);
 devs = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
 if (devs==INVALID_HANDLE_VALUE) return h;

 for (i=0;;i++) {
  DWORD size = 0;
  PSP_DEVICE_INTERFACE_DETAIL_DATA interface_detail;
  union{
   struct{
    SP_DEVICE_INTERFACE_DATA devinterface;
    SP_DEVINFO_DATA devinfo;
   };
   HIDD_ATTRIBUTES deviceAttributes;
   WCHAR productName[32];
  }s;	// some shared buffers not used the same time (does the optimizer see that?)

  if (h) CloseHandle(h), h=0;
  s.devinterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  if (!SetupDiEnumDeviceInterfaces(devs, 0, &hidGuid, i, &s.devinterface)) break;
	// See how large a buffer we require for the device interface details
  SetupDiGetDeviceInterfaceDetail(devs, &s.devinterface, NULL, 0, &size, 0);
  s.devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
  interface_detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR,size);
  if (!interface_detail) continue;
  interface_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  s.devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
  if (!SetupDiGetDeviceInterfaceDetail(devs, &s.devinterface, interface_detail, size, 0, &s.devinfo)) {
   LocalFree(interface_detail);	// ignore this entry in case of error
   continue;
  }
  h = CreateFile(interface_detail->DevicePath, GENERIC_READ|GENERIC_WRITE,
    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  LocalFree(interface_detail);
  if (h == INVALID_HANDLE_VALUE) h = 0;
  if (!h) continue;
  if (!HidD_GetAttributes(h, &s.deviceAttributes)) continue;
  if (*(DWORD*)&s.deviceAttributes.VendorID != 0x06B316C0) continue;	// not mine *)
  if (!n) break;	// found my device
  n--;			// iterate to my next device
 }
 SetupDiDestroyDeviceInfoList(devs);
 return h;
}

// Annahme über USB2LPT: Es ist LPT2 oder LPT1
// Bei PowerSDR muss als Adresse 378h eingestellt sein.
// Es findet kein Cacheing der OUT-Befehle statt.
// TODO: Ein HID-kompatibles Zusatzinterface entschärft das
// Treibersignierungsproblem unter x64-Systemen

HANDLE hAccess;
bool HidMode;
HIDP_CAPS HidCaps;

EXTERN_C _declspec(dllexport) void InitPortTalk(void) {
 hAccess=OpenUsbHid(0);
 if (hAccess) {
  HidMode=true;
  PHIDP_PREPARSED_DATA pd;
  HidD_GetPreparsedData(hAccess,&pd);
  HidP_GetCaps(pd,&HidCaps);
  HidD_FreePreparsedData(pd);
  return;
 }
 hAccess=CreateFile(T("LPT2"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
 if (hAccess==INVALID_HANDLE_VALUE)
   hAccess=CreateFile(T("LPT1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
 if (hAccess==INVALID_HANDLE_VALUE) MessageBox(0,T("No access to USB2LPT!"),NULL,0);
}

EXTERN_C _declspec(dllexport) void ExitPortTalk(void) {
 CloseHandle(hAccess); HidMode=false;
}

EXTERN_C _declspec(dllexport) BYTE inport(WORD a) {
 BYTE IoData[8];
 IoData[0]=1;
 IoData[1]=(a-0x378)|0x10;	// Lese-Bit
 if (HidMode) {
  HidD_SetFeature(hAccess,IoData,HidCaps.FeatureReportByteLength);
  HidD_GetFeature(hAccess,IoData,HidCaps.FeatureReportByteLength);
 }else{
  DWORD BytesRet;
  DeviceIoControl(hAccess,
    CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS),
    IoData+1,1,IoData+1,1,&BytesRet,NULL);
 }
 return IoData[1];
}

EXTERN_C _declspec(dllexport) void outport(WORD a, BYTE b) {
 BYTE IoData[8];
 IoData[0]=2;
 IoData[1]=a-0x378;
 IoData[2]=b;
 if (HidMode) {
  HidD_SetFeature(hAccess,IoData,HidCaps.FeatureReportByteLength);
 }else{
  DWORD BytesRet;
  DeviceIoControl(hAccess,
    CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS),
    IoData+1,2,NULL,0,&BytesRet,NULL);
 }
}

EXTERN_C BOOL WINAPI _DllMainCRTStartup(HINSTANCE hDll,DWORD dwReason,LPVOID) {
 switch (dwReason) {
  case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hDll); break;
 }
 return TRUE;
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded