TL866II Wine implementation

This commit is contained in:
radiomanV
2018-05-12 23:07:40 +03:00
parent 35a910dc1c
commit ccfd1b4a82
8 changed files with 638 additions and 0 deletions

111
wine/TL866II/Makefile Normal file
View 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
View 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

Binary file not shown.

505
wine/TL866II/usb.c Normal file
View 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;
}