Hello all Wine developers,
[the second attempt to send, is the list subscribers only?]
the firs I would like to express my respect to the work done.
Now to one of our application, we maintain open-source chromatographic software CHROMuLAN
https://sourceforge.net/projects/chromulan/
Unfortunately, it is written in Delphi (version 6 used) and we have not resources to port it to run native on Linux even that Linux is for last 18 years our main development platform for embedded hardware design and development. Our long term is to port application to Lazarus/FPC or even rewrite in in Qt but that is not option now.
Fortunately, the CHROMuLAN application runs quite well under latest Wine version. But we have problem with access to the data acquisition hardware.
The devices are connected to computer through special protocol (uLAN) RS-485 network. We have drivers for Linux (the firs platform), Windows (even 64-bit tested) and other targets. All for PCI, RS-232/485 converters and PCI RS-485 addon cards. Whole stack even runs under ReactOS in QEMU now. But Wine is more pleasant solution when someone uses Linux as his/her main desktop system.
https://sourceforge.net/projects/ulan/
Problem is that I loke to provide driver API to the Wine application. The real windows driver is KMD/WMD "ul_wdm.sys" which is registered as "\\.\UL_DRV" by IoCreateDevice and IoCreateSymbolicLink. Driver provides some context per each open and then read, write and iocts are used.
We have exactly the same drive for Linux (x86, 64-bit, MIPS, ARM, PowerPC) with same functionality but Linux IOCTLs numbers are built different way and there are some slight differences caused by differences in Win API IOCTLs processing and Windows does not support poll equivalent for devices too.
I have studied Wine and wineserver more times and have not found how to achieve provision of the Linux driver to the Wine application. Or more or less found that there would be problem because wineserver seems to deliver only IOCTLs events. But I was not sure so I have finally proven that by trial.
I have written DLL/SYS as a driver supporting all required IRP_MJ_xxx and IOCTLs in the style of KMD/WMD driver and implemented functions as calling to the Linux "/dev/ulan" operation equivalents.
But it really does not work. Only IOCTLs are delivered to the ul_drv.sys and even that fails because open context is not setup. Pointer irpStack->FileObject is filled with 0x66666666.
You can find my attempt at
http://cmp.felk.cvut.cz/~pisa/ulan/wine/
Now to the questions,
Is there some mechanism in Wine which I could use? Is there chance to do that as little intrusive (i.e. DLL) that it can be acceptable for Wine mainline?
It seems that serial port device somehow solves similar problem but is seems to be hardwired to wineserv.
As for my case, it is possible that read and write to the open /dev/ulan file are done directly from context of application if it receives Linux filehandle into wine/dlls/ntdll/file.c .
If the new FD_TYPE_ (FD_TYPE_SERIAL) is defined then all processing can be done in Linux native NTDLL. Even IOCTLs translation because they are really straightforward (like wine-git/dlls/ntdll/serial.c does in COMM_DeviceIoControl). But such solution seems intrusive to me.
On the other hand the structure struct object_ops in wine/wine/server/object.h seems to provide all operations.
Can I use some registration in the server to solve access? I am missing something? Is there some suggestion which approach to take?
Some reasonable simple solution is preferred because if projects takes too much time it would even more postpone possibility to start real application porting.
Thanks for each possible advice,
Pavel -- Pavel Pisa e-mail: pisa@cmp.felk.cvut.cz www: http://cmp.felk.cvut.cz/~pisa university: http://dce.fel.cvut.cz/ company: http://www.pikron.com/
I don't know much about this, but it sounds like a driver is the right way to do this. It's probably just a case of Wine's driver support not being good enough yet to support what you want to do. So the less intrusive/hacky way to fix this would be to improve Wine's driver support, ideally to a point where you can run the same driver on Windows and Wine (but I don't know if that's possible).
I think the limitation of Wine being unable to do file i/o without a native fd has also come up with message mode named pipes, which are still unimplemented and are semantically different from any native file object we can use.
Details of Wine's implementation, such as object_ops or the translation of ioctls, are generally not exposed to windows or winelib software, because they can change. The correct long term solution is to implement the Windows API which cannot change and is within Wine's scope.
Since you're not prepared to spend a lot of time improving Wine's driver support, it sounds like modifying core parts of Wine specifically to support your application is the best approach.
Hi Vincent, Pavel,
On Tue, Jul 2, 2013 at 8:44 AM, Vincent Povirk madewokherd@gmail.comwrote:
Since you're not prepared to spend a lot of time improving Wine's driver support, it sounds like modifying core parts of Wine specifically to support your application is the best approach.
An alternative is to modify your application for use with Wine. What others have suggested in similar situations is to build a Linux application that speaks to the device driver directly, and provides a socket interface, then use sockets from the Windows program to talk to the device. This is usually straightforward enough, and doesn't require learning lots of Wine internals to get working. --Juan
What others have suggested in similar situations is to build a Linux application that speaks to the device driver directly, and provides a socket interface, then use sockets from the Windows program to talk to the device.
I didn't think of that. A winelib dll providing an API for directly accessing your devices (which you can use from a normal Windows program) might be simpler than a separate process if you're willing to modify the application.
Hello all,
thanks much for replies.
On Tuesday 02 of July 2013 18:15:28 Vincent Povirk wrote:
What others have suggested in similar situations is to build a Linux application that speaks to the device driver directly, and provides a socket interface, then use sockets from the Windows program to talk to the device.
I didn't think of that. A winelib dll providing an API for directly accessing your devices (which you can use from a normal Windows program) might be simpler than a separate process if you're willing to modify the application.
Do you mean by winelib dll that the wine/Liunux native .so style DLL is built which is linked/imported through fakedlib to the application? That looks like feasible solution and I would consider this solution if there is interrest in the application in Linux community and not enough resource is find to port it as full Linux native version.
How is it with wine version dependency if the wine .so style DLL uses only bunch of Linux calls (open, close, read, write, ioctl) and exports some small set of the functions to the application?
Another suggestion to use socket is also reasonable. In the fact we have support for indirect uLAN access over TCP/IP implemented in other utilities and programs but for this actual application it is missing and would require more intrusive modifications. Its design is quite old but it provides still valuable services to many old and new users.
I have done some more search to find narrow passes which limits my initial idea of the driver based solution. I am sending my dump there because it can be usesfull to somebody else (or even to me if I find time one day and return to the problem).
The driver is run by Wine in the separate process. This process calls get_next_device_request which is processed on the Wine Server side in
wine-git/server/device.c: /* retrieve the next pending device ioctl request */ DECL_HANDLER(get_next_device_request)
Even that name suggest that it is processing generic requests, actual implementation is really minimal and allows only to encode simple IOCTLs which use BUFFERED method to pass data.
But extension to more complete version is possible. It is questionable if more fields and operations codes should be added or if the better way to achieve complete functionality is to provide mechanism to pass whole IRP from wine server to the service tasks. This would be more close to the real Windows implementation and original idea of microkernel based OS. But whole IRP is quite huge and some mechanism to pass it and associated data through shared memory would be probably much faster.
In both cases, there should be maintained/exchanged at least value of the fields
StackPtr->FileObject->FsContext StackPtr->FileObject->FsContext2
where drivers can store their context specific for each device open instance (IRP_MJ_CREATE). It has to be stored and read again from the HANDLE structure created/associated with file in wine/server/directory.c.
Next operations needs to be propagated for our driver (and probably would cover needs of significant range of other drivers too)
ulan_driver = driver; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ulan_dispatch; driver->MajorFunction[IRP_MJ_CREATE] = ulan_dispatch; driver->MajorFunction[IRP_MJ_CLOSE] = ulan_dispatch; driver->MajorFunction[IRP_MJ_READ] = ulan_dispatch; driver->MajorFunction[IRP_MJ_WRITE] = ulan_dispatch; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ulan_dispatch; driver->MajorFunction[IRP_MJ_CLEANUP] = ulan_dispatch;
The analysis of the side of the started service
C:\windows\system32\winedevice.exe uL_Drv
wine/programs/winedevice/device.c:ServiceMain() wine_ntoskrnl_main_loop( stop_event );
wine/dlls/ntoskrnl.exe/ntoskrnl.c: wine_ntoskrnl_main_loop( HANDLE stop_event )
SERVER_START_REQ( get_next_device_request )
process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size, void *out_buff, ULONG *out_size ) PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
Pointer irpStack->FileObject is filled with 0x66666666.
Good source of information how full IRP setup should work can be found in React OS sources
reactos/reactos/reactos/ntoskrnl/io/iomgr/irp.c
and
reactos/reactos/reactos/ntoskrnl/io/iomgr/iofunc.c:IopDeviceFsIoControl including FileObject
/* Setup the IRP */ Irp->UserIosb = IoStatusBlock; Irp->UserEvent = EventObject; Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine; Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext; Irp->Cancel = FALSE; Irp->CancelRoutine = NULL; Irp->PendingReturned = FALSE; Irp->RequestorMode = PreviousMode; Irp->MdlAddress = NULL; Irp->AssociatedIrp.SystemBuffer = NULL; Irp->Flags = 0; Irp->Tail.Overlay.AuxiliaryBuffer = NULL; Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->Tail.Overlay.Thread = PsGetCurrentThread();
/* Set stack location settings */ StackPtr = IoGetNextIrpStackLocation(Irp); StackPtr->FileObject = FileObject; StackPtr->MajorFunction = IsDevIoCtl ? IRP_MJ_DEVICE_CONTROL : IRP_MJ_FILE_SYSTEM_CONTROL; StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */ StackPtr->Control = 0; StackPtr->Flags = 0; StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
/* Set the IOCTL Data */ StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode; StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; StackPtr->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
This is example for IOCTL. The other operations need again similar but individual setup.
So I hope that this information could be usesfull for somebody.
May it be that even my skeleton of the "native" driver extracted from Wine sources can be usesfull for somebody who needs to substitute functionality of some simpler driver which functionality is fully implemented in IOCTL and without per open context.
http://cmp.felk.cvut.cz/~pisa/ulan/wine/
Thanks again for advises and your work,
Pavel
Do you mean by winelib dll that the wine/Liunux native .so style DLL is built which is linked/imported through fakedlib to the application? That looks like feasible solution and I would consider this solution if there is interrest in the application in Linux community and not enough resource is find to port it as full Linux native version.
I don't know what "fakedlib" is. I know you can use LoadLibrary/GetProcAddress, or create a Windows DLL with the same abi and link to that. There may be some other way to generate a .lib file that I'm not aware of.
How is it with wine version dependency if the wine .so style DLL uses only bunch of Linux calls (open, close, read, write, ioctl) and exports some small set of the functions to the application?
The abi for winelib .dll.so files has been stable for a long time, but of course such files will be specific to Linux and will also rely on the abi of libraries they import (including glibc, which means it's a good idea to build on a relatively old distribution for better compatibility). I think it's possible to rename the .dll.so file to .dll and put it with your application's files, if you don't want to ship your own version of Wine or require a special build.
I have done some more search to find narrow passes which limits my initial idea of the driver based solution. I am sending my dump there because it can be usesfull to somebody else (or even to me if I find time one day and return to the problem).
This goes over my head. It sounds like you know a lot about Windows drivers, and it's too bad you don't have time to help us with that.