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