libcasio/src/stream/builtin/windows/find.c

117 lines
4.0 KiB
C

/* ****************************************************************************
* stream/builtin/windows/find.c -- find a Windows API USB stream.
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libcasio.
* libcasio is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libcasio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libcasio; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************* */
#include "windows.h"
#ifndef LIBCASIO_DISABLED_WINDOWS
/**
* casio_windows_find_usb:
* Find the Microsoft Windows device path.
*
* @arg path the path to allocate.
* @arg vid the vendor ID (0x0000 to 0xffff)
* @arg pid the product ID (0x0000 to 0xffff)
* @return the error code (0 if ok).
*/
int CASIO_EXPORT casio_windows_find_usb(char **path,
unsigned int vid, unsigned int pid)
{
int i; DWORD werr;
char *devpath = NULL, vidpid[20];
HDEVINFO DeviceInfoSet;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
/* make the vid/pid string */
sprintf(vidpid, "#vid_%04x&pid_%04x", vid, pid);
/* get the device information set (chained list) */
msg((ll_info, "Getting the device info set"));
DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE,
NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
werr = GetLastError();
msg((ll_fatal, "Device info gathering failed! Error 0x%08lX", werr));
return (casio_error_notfound);
}
/* browse this set, setup */
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
msg((ll_info, "Enumerating interfaces"));
for (i = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL,
&GUID_DEVINTERFACE_USB_DEVICE, i, &DeviceInterfaceData); i++) {
/* make the local variables */
DWORD RequiredSize = 0; const char *Path;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
/* get the detail size */
msg((ll_info, "Getting interface information detail size"));
if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
&DeviceInterfaceData, NULL, 0, &RequiredSize, NULL) &&
(werr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) {
msg((ll_error, "Error getting this size: 0x%08lX", werr));
continue;
}
/* allocate detail space */
msg((ll_info,
"Allocating space for interface information detail (%luo)",
RequiredSize));
DeviceInterfaceDetailData = casio_alloc(RequiredSize, 1);
if (!DeviceInterfaceDetailData) {
msg((ll_error, "Memory allocation failed. Oh well."));
break ;
}
DeviceInterfaceDetailData->cbSize =
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
/* get the detail */
msg((ll_info, "Getting interface information detail"));
if (!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
&DeviceInterfaceData, DeviceInterfaceDetailData, RequiredSize,
NULL, NULL)) {
werr = GetLastError();
msg((ll_error, "Error getting the interface information detail: "
"0x%08lX", werr));
continue;
}
/* check if it corresponds */
Path = DeviceInterfaceDetailData->DevicePath;
msg((ll_info, "Stumbled across: %s", Path));
if (strstr(Path, vidpid)) {
devpath = casio_alloc(strlen(Path) + 1, 1);
if (!devpath) break;
strcpy(devpath, Path);
}
/* free the allocated detail */
casio_free(DeviceInterfaceDetailData);
if (devpath) break ;
}
/* destroy the device information set */
msg((ll_info, "Destroying the device information set"));
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
if (!devpath) return (casio_error_notfound);
*path = devpath;
return (0);
}
#endif