mirror of
https://github.com/radiomanV/TL866.git
synced 2026-03-10 02:07:05 +01:00
TL866II Wine implementation
This commit is contained in:
111
wine/TL866II/Makefile
Normal file
111
wine/TL866II/Makefile
Normal file
@@ -0,0 +1,111 @@
|
||||
### Generated by Winemaker 0.8.4
|
||||
###
|
||||
### Invocation command line was
|
||||
### /usr/bin/winemaker -lusb-1.0 -ludev --dll --nosource-fix --nobackup --nomsvcrt --nodlls ./
|
||||
|
||||
|
||||
SRCDIR = .
|
||||
SUBDIRS =
|
||||
DLLS = usb.dll
|
||||
LIBS =
|
||||
EXES =
|
||||
|
||||
|
||||
|
||||
### Common settings
|
||||
|
||||
CEXTRA =-m32 -mincoming-stack-boundary=2
|
||||
CXXEXTRA =
|
||||
RCEXTRA =
|
||||
DEFINES =
|
||||
INCLUDE_PATH =
|
||||
DLL_PATH =
|
||||
DLL_IMPORTS =
|
||||
LIBRARY_PATH =
|
||||
LIBRARIES = -lusb-1.0 -ludev
|
||||
|
||||
|
||||
### usb.dll sources and settings
|
||||
|
||||
usb_dll_MODULE = usb.dll
|
||||
usb_dll_C_SRCS = usb.c
|
||||
usb_dll_CXX_SRCS =
|
||||
usb_dll_RC_SRCS =
|
||||
usb_dll_LDFLAGS = -shared -m32
|
||||
usb_dll_ARFLAGS =
|
||||
usb_dll_DLL_PATH =
|
||||
usb_dll_DLLS =
|
||||
usb_dll_LIBRARY_PATH =
|
||||
usb_dll_LIBRARIES =
|
||||
|
||||
usb_dll_OBJS = $(usb_dll_C_SRCS:.c=.o) \
|
||||
$(usb_dll_CXX_SRCS:.cpp=.o) \
|
||||
$(usb_dll_RC_SRCS:.rc=.res)
|
||||
|
||||
|
||||
|
||||
### Global source lists
|
||||
|
||||
C_SRCS = $(usb_dll_C_SRCS)
|
||||
CXX_SRCS = $(usb_dll_CXX_SRCS)
|
||||
RC_SRCS = $(usb_dll_RC_SRCS)
|
||||
|
||||
|
||||
### Tools
|
||||
|
||||
CC = winegcc
|
||||
CXX = wineg++
|
||||
RC = wrc
|
||||
AR = ar
|
||||
|
||||
|
||||
### Generic targets
|
||||
|
||||
all: $(SUBDIRS) $(DLLS:%=%.so) $(LIBS) $(EXES)
|
||||
|
||||
### Build rules
|
||||
|
||||
.PHONY: all clean dummy
|
||||
|
||||
$(SUBDIRS): dummy
|
||||
@cd $@ && $(MAKE)
|
||||
|
||||
# Implicit rules
|
||||
|
||||
.SUFFIXES: .cpp .cxx .rc .res
|
||||
DEFINCL = $(INCLUDE_PATH) $(DEFINES) $(OPTIONS)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $(CEXTRA) $(DEFINCL) -o $@ $<
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) -c $(CXXFLAGS) $(CXXEXTRA) $(DEFINCL) -o $@ $<
|
||||
|
||||
.cxx.o:
|
||||
$(CXX) -c $(CXXFLAGS) $(CXXEXTRA) $(DEFINCL) -o $@ $<
|
||||
|
||||
.rc.res:
|
||||
$(RC) $(RCFLAGS) $(RCEXTRA) $(DEFINCL) -fo$@ $<
|
||||
|
||||
# Rules for cleaning
|
||||
|
||||
CLEAN_FILES = y.tab.c y.tab.h lex.yy.c core *.orig *.rej \
|
||||
\\\#*\\\# *~ *% .\\\#*
|
||||
|
||||
clean:: $(SUBDIRS:%=%/__clean__) $(EXTRASUBDIRS:%=%/__clean__)
|
||||
$(RM) $(CLEAN_FILES) $(RC_SRCS:.rc=.res) $(C_SRCS:.c=.o) $(CXX_SRCS:.cpp=.o)
|
||||
$(RM) $(DLLS:%=%.so) $(LIBS) $(EXES) $(EXES:%=%.so)
|
||||
|
||||
$(SUBDIRS:%=%/__clean__): dummy
|
||||
cd `dirname $@` && $(MAKE) clean
|
||||
|
||||
$(EXTRASUBDIRS:%=%/__clean__): dummy
|
||||
-cd `dirname $@` && $(RM) $(CLEAN_FILES)
|
||||
|
||||
### Target specific build rules
|
||||
DEFLIB = $(LIBRARY_PATH) $(LIBRARIES) $(DLL_PATH) $(DLL_IMPORTS:%=-l%)
|
||||
|
||||
$(usb_dll_MODULE).so: $(usb_dll_OBJS)
|
||||
$(CC) $(usb_dll_LDFLAGS) -o $@ $(usb_dll_OBJS) $(usb_dll_LIBRARY_PATH) $(usb_dll_DLL_PATH) $(DEFLIB) $(usb_dll_DLLS:%=-l%) $(usb_dll_LIBRARIES:%=-l%)
|
||||
|
||||
|
||||
22
wine/TL866II/readme
Normal file
22
wine/TL866II/readme
Normal file
@@ -0,0 +1,22 @@
|
||||
Simple low level winelib usb wrapper for Xgpro V7.xx
|
||||
This version will autodetect the Xgpro.exe version.
|
||||
|
||||
Add the following rule to the udev subsystem:
|
||||
open terminal and as root type:
|
||||
#echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="a466", ATTRS{idProduct}=="0a53", GROUP="plugdev", MODE="0666"' > /etc/udev/rules.d/51-minipro.rules
|
||||
#udevadm trigger
|
||||
|
||||
|
||||
How to install:
|
||||
1. Install wine
|
||||
2. Copy the provided setupapi.dll file in the minipro folder
|
||||
3. Run the Minipro.exe
|
||||
|
||||
|
||||
How to compile:
|
||||
1. Install wine, wine-devel, libusb-devel, libudev-devel packages
|
||||
2. Run make
|
||||
3. Rename usb.dll.so as setupapi.dll and copy this file in the minipro folder
|
||||
4. Run the Minipro.exe
|
||||
|
||||
|
||||
BIN
wine/TL866II/setupapi.dll
Executable file
BIN
wine/TL866II/setupapi.dll
Executable file
Binary file not shown.
505
wine/TL866II/usb.c
Normal file
505
wine/TL866II/usb.c
Normal file
@@ -0,0 +1,505 @@
|
||||
#define __WINESRC__
|
||||
#define __CYGWIN__
|
||||
#define _GNU_SOURCE
|
||||
|
||||
|
||||
#include <glob.h>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <libudev.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnt.h>
|
||||
#include <dbt.h>
|
||||
|
||||
#define TL866_VID 0xA466
|
||||
#define TL866_PID 0x0A53
|
||||
|
||||
|
||||
typedef struct {
|
||||
HANDLE InterfaceHandle;
|
||||
UCHAR PipeID;
|
||||
PUCHAR Buffer;
|
||||
ULONG BufferLength;
|
||||
PULONG LengthTransferred;
|
||||
LPOVERLAPPED Overlapped;
|
||||
}Args;
|
||||
|
||||
//replacement functions for minipro. Function prototypes and calling convention must be the same as in Xgpro.exe, otherwise the application will crash.
|
||||
int open_devices(int *error);
|
||||
void close_devices();
|
||||
HANDLE __stdcall RegisterDeviceNotifications(HANDLE hRecipient, LPVOID NotificationFilter, DWORD Flags);
|
||||
BOOL __stdcall WinUsb_SetPipePolicy(HANDLE InterfaceHandle, UCHAR PipeID, ULONG PolicyType, ULONG ValueLength, PVOID Value);
|
||||
BOOL __stdcall WinUsb_Transfer(HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped);
|
||||
|
||||
//helper functions
|
||||
BOOL patch_minipro();
|
||||
BOOL patch_function(char *library, char *func, void *funcaddress);
|
||||
void async_transfer(Args *args);
|
||||
void notifier_function();
|
||||
int get_device_count();
|
||||
|
||||
|
||||
//Global variables
|
||||
libusb_device_handle *device_handle[4];
|
||||
libusb_context *ctx;
|
||||
libusb_device **devs;
|
||||
|
||||
HANDLE h_thread;
|
||||
|
||||
HWND hWnd;
|
||||
BOOL cancel;
|
||||
HANDLE *usb_handle;
|
||||
HANDLE *winusb_handle;
|
||||
int *devices_count;
|
||||
|
||||
//These are functions signature extracted from Xgpro.exe and should be compatible from V7.0 and above.
|
||||
const unsigned char open_devices_pattern[] = { 0x53,0x57,0x6A,0x00,0x68,0x80,0x00,0x00,0x40,0x6A,0x03,0x6A,0x00,0x6A,0x03,0x68 };
|
||||
|
||||
|
||||
|
||||
BOOL patch_function(char *library, char *func, void *funcaddress)
|
||||
{
|
||||
DWORD dwOldProtection;
|
||||
DWORD func_addr = 0;
|
||||
|
||||
void *BaseAddress = GetModuleHandleA(NULL);
|
||||
PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)((PBYTE)BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew);
|
||||
PIMAGE_IMPORT_DESCRIPTOR ImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)BaseAddress + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
//Search for library in the IAT
|
||||
while (ImpDesc->Characteristics && ImpDesc->Name) {
|
||||
if (strcasecmp(BaseAddress + ImpDesc->Name, library) == 0) {
|
||||
break;//Found it!
|
||||
}
|
||||
ImpDesc++;
|
||||
}
|
||||
|
||||
|
||||
//check if the library was found in the IAT
|
||||
if(!ImpDesc->Characteristics)
|
||||
{
|
||||
printf("%s was not found in the IAT.\n", library);
|
||||
return FALSE;//nope, exit with error.
|
||||
}
|
||||
|
||||
//Get the address of function in library
|
||||
DWORD_PTR ProcAddress = (DWORD_PTR)GetProcAddress(GetModuleHandleA(library), func);
|
||||
|
||||
//Find the address in the thunk table
|
||||
PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(BaseAddress + ImpDesc->FirstThunk);
|
||||
while (thunk->u1.Function)
|
||||
{
|
||||
if ((DWORD_PTR)thunk->u1.Function == ProcAddress)
|
||||
{
|
||||
//if found, patch it to point to our custom function
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
VirtualQuery(&thunk->u1.Function, &info, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
VirtualProtect(info.BaseAddress, info.RegionSize, PAGE_READWRITE, &dwOldProtection);
|
||||
func_addr = thunk->u1.Function;
|
||||
thunk->u1.Function = (DWORD_PTR)funcaddress;
|
||||
VirtualProtect(info.BaseAddress, info.RegionSize, info.Protect, &dwOldProtection);
|
||||
|
||||
}
|
||||
|
||||
thunk++;
|
||||
}
|
||||
|
||||
//check if the patch was ok.
|
||||
if (!func_addr)
|
||||
{
|
||||
printf("%s was not found in %s.\n", func, library);
|
||||
return FALSE;//nope, exit with error.
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//Patcher function. Called from DllMain. Return TRUE if patch was ok and continue with program loading or FALSE to exit with error.
|
||||
BOOL patch_minipro()
|
||||
{
|
||||
|
||||
//Get the BaseAddress, NT Header and Image Import Descriptor
|
||||
void *BaseAddress = GetModuleHandleA(NULL);
|
||||
PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)((PBYTE)BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew);
|
||||
|
||||
//Patch the Linux incompatible functions functions
|
||||
if(!patch_function("user32.dll", "RegisterDeviceNotificationA", &RegisterDeviceNotifications))
|
||||
return FALSE;
|
||||
|
||||
if(!patch_function("winusb.dll", "WinUsb_SetPipePolicy", &WinUsb_SetPipePolicy))
|
||||
return FALSE;
|
||||
|
||||
if(!patch_function("winusb.dll", "WinUsb_WritePipe", &WinUsb_Transfer))
|
||||
return FALSE;
|
||||
|
||||
if(!patch_function("winusb.dll", "WinUsb_ReadPipe", &WinUsb_Transfer))
|
||||
return FALSE;
|
||||
|
||||
|
||||
//Searching for functions signature in code section.
|
||||
void *p_opendevices = memmem(BaseAddress + NtHeader->OptionalHeader.BaseOfCode, NtHeader->OptionalHeader.SizeOfCode, &open_devices_pattern, sizeof(open_devices_pattern)) - 0x1D;
|
||||
void *p_closedevices = (void*)(*(int*)((unsigned char*)p_opendevices + 5)) + (DWORD)((unsigned char*)p_opendevices + 9);
|
||||
void *p_winusbhandle = (void*)(*(int*)((unsigned char*)p_closedevices + 0x12));
|
||||
void *p_usbhandle = (void*)(*(int*)((unsigned char*)p_closedevices + 0x2));
|
||||
void *p_devicescount= (void*)(*(int*)((unsigned char*)p_opendevices + 0xAF));
|
||||
|
||||
//check if all pointers are o.k.
|
||||
if (!p_opendevices)
|
||||
{
|
||||
printf("Functions signature not found! Unknown MiniPro version.\n");
|
||||
return FALSE;//nope, exit with error.
|
||||
}
|
||||
|
||||
|
||||
//Print debug info.
|
||||
unsigned char *version = memmem(BaseAddress, NtHeader->OptionalHeader.SizeOfImage, "Xgpro v", 7);
|
||||
if (version) printf("Found %s\n", version);
|
||||
printf("Base Address = 0x%08X\n", (DWORD)BaseAddress);
|
||||
printf("Code section = 0x%08X,0x%08X\n", (DWORD)BaseAddress + NtHeader->OptionalHeader.BaseOfCode, (DWORD)NtHeader->OptionalHeader.SizeOfCode);
|
||||
printf("Open Devices found at 0x%08X\n", (DWORD)p_opendevices);
|
||||
printf("Close Devices found at 0x%08X\n", (DWORD)p_closedevices);
|
||||
printf("Usb Handle found at 0x%08X\n", (DWORD)p_usbhandle);
|
||||
printf("WinUsb Handle found at 0x%08X\n", (DWORD)p_winusbhandle);
|
||||
printf("Devices count found at 0x%08X\n", (DWORD)p_devicescount);
|
||||
|
||||
|
||||
//Patch all low level functions in MiniPro.exe to point to our custom functions.
|
||||
BYTE t[] = { 0x68, 0, 0, 0, 0, 0xc3 };// push xxxx, ret; an absolute Jump replacement.
|
||||
DWORD *p_func = (DWORD*)&t[1];
|
||||
DWORD dwOldProtection;
|
||||
|
||||
//Initialize the usb handle address.
|
||||
usb_handle = p_usbhandle;
|
||||
winusb_handle = p_winusbhandle;
|
||||
devices_count = p_devicescount;
|
||||
VirtualProtect(BaseAddress + NtHeader->OptionalHeader.BaseOfCode, NtHeader->OptionalHeader.SizeOfCode, PAGE_READWRITE, &dwOldProtection);//unprotect the code memory section
|
||||
|
||||
//patch Open_Devices function
|
||||
*p_func = (DWORD)&open_devices;
|
||||
memcpy(p_opendevices, t, 6);
|
||||
|
||||
//patch close_devices function
|
||||
*p_func = (DWORD)&close_devices;
|
||||
memcpy(p_closedevices, t, 6);
|
||||
|
||||
VirtualProtect(BaseAddress + NtHeader->OptionalHeader.BaseOfCode, NtHeader->OptionalHeader.SizeOfCode, dwOldProtection, &dwOldProtection);//restore the old protection
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Minipro replacement functions
|
||||
int open_devices(int *error)
|
||||
{
|
||||
printf("Open devices.\n");
|
||||
close_devices();
|
||||
device_handle[0] = NULL;
|
||||
device_handle[1] = NULL;
|
||||
device_handle[2] = NULL;
|
||||
device_handle[3] = NULL;
|
||||
devs = NULL;
|
||||
|
||||
libusb_init(&ctx);//initialize a new session
|
||||
libusb_set_debug(ctx, 3);//set verbosity level
|
||||
|
||||
|
||||
usb_handle[0] = INVALID_HANDLE_VALUE;
|
||||
usb_handle[1] = INVALID_HANDLE_VALUE;
|
||||
usb_handle[2] = INVALID_HANDLE_VALUE;
|
||||
usb_handle[3] = INVALID_HANDLE_VALUE;
|
||||
|
||||
winusb_handle[0] = INVALID_HANDLE_VALUE;
|
||||
winusb_handle[1] = INVALID_HANDLE_VALUE;
|
||||
winusb_handle[2] = INVALID_HANDLE_VALUE;
|
||||
winusb_handle[3] = INVALID_HANDLE_VALUE;
|
||||
|
||||
*devices_count = 0;
|
||||
|
||||
int devices_found = 0, i, ret;
|
||||
struct libusb_device_descriptor desc;
|
||||
int count = libusb_get_device_list(ctx, &devs);
|
||||
|
||||
if (count < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = libusb_get_device_descriptor(devs[i], &desc);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (TL866_PID == desc.idProduct && TL866_VID == desc.idVendor)
|
||||
{
|
||||
if (libusb_open(devs[i], &device_handle[devices_found]) == LIBUSB_SUCCESS &&
|
||||
libusb_claim_interface(device_handle[devices_found], 0) == LIBUSB_SUCCESS)
|
||||
{
|
||||
usb_handle[devices_found] = (HANDLE)devices_found;
|
||||
winusb_handle[devices_found] = (HANDLE)devices_found;
|
||||
devices_found++;
|
||||
*devices_count = devices_found;
|
||||
if (devices_found == 4)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void close_devices()
|
||||
{
|
||||
printf("Close devices.\n");
|
||||
if (devs != NULL)
|
||||
{
|
||||
|
||||
int i;;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (device_handle[i] != NULL)
|
||||
{
|
||||
//libusb_release_interface(device_handle[i], 0);
|
||||
libusb_close(device_handle[i]);
|
||||
device_handle[i] = NULL;
|
||||
}
|
||||
}
|
||||
libusb_free_device_list(devs, 1);
|
||||
libusb_exit(ctx);//close session
|
||||
devs = NULL;;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
HANDLE __stdcall RegisterDeviceNotifications(HANDLE hRecipient, LPVOID NotificationFilter, DWORD Flags)
|
||||
{
|
||||
|
||||
printf("RegisterDeviceNotifications hWnd=%X4\n", (unsigned int)hRecipient);
|
||||
hWnd = hRecipient;
|
||||
h_thread = CreateThread(NULL, 0, (void*)notifier_function, NULL, 0, NULL);
|
||||
if(! h_thread)
|
||||
printf("Thread notifier failed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//winusb implemented functions.
|
||||
BOOL __stdcall WinUsb_SetPipePolicy(HANDLE InterfaceHandle, UCHAR PipeID, ULONG PolicyType, ULONG ValueLength, PVOID Value)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//Asynchronous transfer for WinUsb_ReadPipe/WinUsb_WritePipe.
|
||||
void async_transfer(Args *args)
|
||||
{
|
||||
libusb_bulk_transfer(device_handle[(int)args->InterfaceHandle], args->PipeID, args->Buffer, args->BufferLength, args->LengthTransferred, 10000);
|
||||
SetEvent(args->Overlapped->hEvent);//signal the event to release the waiting object.
|
||||
free(args);//Free the malloced args.
|
||||
}
|
||||
|
||||
|
||||
//WinUsb_ReadPipe/winUsb_WritePipe LibUsb implementation.
|
||||
BOOL __stdcall WinUsb_Transfer(HANDLE InterfaceHandle, UCHAR PipeID, PUCHAR Buffer, ULONG BufferLength, PULONG LengthTransferred, LPOVERLAPPED Overlapped)
|
||||
{
|
||||
if (InterfaceHandle == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
if (device_handle[(int)InterfaceHandle] == NULL)
|
||||
return FALSE;
|
||||
int ret;
|
||||
if(Overlapped != NULL)//If an asynchronous transfer is needed then pack all the arguments to an Arg structure and pass them to a new thread and return immediately.
|
||||
{
|
||||
ResetEvent(Overlapped->hEvent);
|
||||
Args *args = malloc(sizeof(*args));
|
||||
args->InterfaceHandle = InterfaceHandle;
|
||||
args->PipeID = PipeID;
|
||||
args->Buffer = Buffer;
|
||||
args->BufferLength = BufferLength;
|
||||
args->LengthTransferred = LengthTransferred;
|
||||
args->Overlapped = Overlapped;
|
||||
CreateThread(NULL, 0, (void*)async_transfer, args, 0, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
else//Just an synchronous transfer is needed; just call the libusb_bulk_transfer.
|
||||
{
|
||||
ret = libusb_bulk_transfer(device_handle[(int)InterfaceHandle], PipeID, Buffer, BufferLength, LengthTransferred, 10000);
|
||||
}
|
||||
|
||||
return (ret == LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void notifier_function()
|
||||
{
|
||||
|
||||
struct udev *udev;
|
||||
struct udev_monitor *mon;
|
||||
struct udev_device *dev;
|
||||
|
||||
const GUID guid = {0xE7E8BA13,0x2A81,0x446E,{0xA1,0x1E,0x72,0x39,0x8F,0xBD,0xA8,0x2F}};
|
||||
|
||||
DEV_BROADCAST_DEVICEINTERFACE_W DevBi;
|
||||
DevBi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W);
|
||||
DevBi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
DevBi.dbcc_classguid = guid;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
printf("Can't create udev\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mon = udev_monitor_new_from_netlink(udev, "udev");
|
||||
if (!mon)
|
||||
{
|
||||
printf("NetLink not available!\n");
|
||||
return;
|
||||
}
|
||||
int count = get_device_count();
|
||||
if (count == -1)
|
||||
{
|
||||
printf("udev error.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL);
|
||||
udev_monitor_enable_receiving(mon);
|
||||
int fd = udev_monitor_get_fd(mon);
|
||||
|
||||
cancel = FALSE;
|
||||
while (!cancel) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int ret;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ret = select(fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (ret > 0 && FD_ISSET(fd, &fds)) {
|
||||
|
||||
dev = udev_monitor_receive_device(mon);
|
||||
if (dev && !strcasecmp(udev_device_get_devtype(dev), "usb_device")) {
|
||||
int count_new;
|
||||
if (!strcasecmp(udev_device_get_action(dev), "add"))
|
||||
{
|
||||
count_new = get_device_count();
|
||||
if (count != count_new)
|
||||
{
|
||||
count = count_new;
|
||||
//printf("device added.\n");
|
||||
close_devices();
|
||||
usleep(100000);
|
||||
SendMessageA(hWnd, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&DevBi);
|
||||
usleep(100000);
|
||||
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!strcasecmp(udev_device_get_action(dev), "remove"))
|
||||
{
|
||||
count_new = get_device_count();
|
||||
if (count != count_new)
|
||||
{
|
||||
count = count_new;
|
||||
//printf("device removed.\n");
|
||||
close_devices();
|
||||
usleep(100000);
|
||||
SendMessageA(hWnd, WM_DEVICECHANGE, DBT_DEVICEREMOVECOMPLETE, (LPARAM)&DevBi);
|
||||
usleep(100000);
|
||||
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
|
||||
}
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
}
|
||||
usleep(10000);
|
||||
}
|
||||
udev_monitor_unref(mon);
|
||||
}
|
||||
|
||||
|
||||
int get_device_count()
|
||||
{
|
||||
struct udev *udev = udev_new();
|
||||
if (!udev)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
struct udev_device *dev;
|
||||
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(enumerate, "usb");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
int count = 0;
|
||||
udev_list_entry_foreach(dev_list_entry, devices)
|
||||
{
|
||||
dev = udev_device_new_from_syspath(udev, udev_list_entry_get_name(dev_list_entry));
|
||||
if (!dev)
|
||||
return -1;
|
||||
|
||||
const char * vid = udev_device_get_sysattr_value(dev, "idVendor");
|
||||
const char * pid = udev_device_get_sysattr_value(dev, "idProduct");;
|
||||
if (vid && pid && strtoul(vid, NULL, 16) == TL866_VID && strtoul(pid, NULL, 16) == TL866_PID)
|
||||
count++;
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
udev_enumerate_unref(enumerate);
|
||||
udev_unref(udev);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_WINE_PREATTACH:
|
||||
return TRUE;
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
printf("Dll Loaded.\n");
|
||||
if (!patch_minipro())
|
||||
{
|
||||
printf("Dll Unloaded.\n");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
cancel = TRUE;
|
||||
WaitForSingleObject(h_thread, 5000);
|
||||
printf("Dll Unloaded.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user