Message: 2 Date: Tue, 9 Dec 2003 14:56:16 -0800 Subject: Adding support for a USB device From: Dan Timis timis@museresearch.com To: wine-devel@winehq.org
Hi,
I need help with supporting a particular USB device under wine. I have to start by saying that although I am an experienced C/C++ programmer with some Linux experience, I have almost no Windows or wine experience.
The Windows code for which I need to provide support uses CreateFile() to get a handle to the device. The name of the device is something like "\.\MyDevice0" "\.\MyDevice1" and so on. Then, the code uses DeviceIoControl() to read and write from/to the device. The requirement is not to change the windows code.
I looked through the wine code and I found this in device.c:
static const struct VxDInfo VxDList[]
I could add another entry into the table and write a deviceio handler (BOOL (*deviceio)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);). I wrote some test code in Linux using libusb reading and writing to the device so I know what to do inside the deviceio handler.
Is this the right approach? If so, what do I need to do to get CreateFile to return the right handle?
I think it really depends on the type of device and the possibility to rewrite the device driver or not.
\.\MyDevice0 is just a device driver name which at some point is registered in the registry with the appropriate VXD, SYS, or WDM driver file. If you know the exact DeviceIOControls called into that driver with its parameters and all, you could rewrite the VXD, SYS or WDM driver to call directly the appropriate Unix device driver calls and maybe compile it as a Winelib driver. With a bit hacking in the CreateFile function it should be possible to call such a driver over DeviceIOControl or you could add the according code to the above mentioned VXDList.
Or should I write an external driver that gets loaded by wine? If so, how would I do that? What are the chances that the Windows driver for this device would just work with wine?
If you don't know these details and want to use the original device driver you are probably out of luck. The current CreateFile implementation is not really up to the task of loading an external native device driver and invoke it over the DeviceIOControl (which could probably be remedied with a little hacking at this point) and what is much more problematic there is little or no support for a lot of the Windows kernel services most device driver usually expect to be able to call. When they are not able to link to one or more of those functions at load time, loading of the device driver will simply fail in Wine, as it does with normal DLL files under all Win32 implementations, too.
Rolf Kalbermatter
Thanks Rolf (and Uwe).
I did some further investigation and it looks like CreateFile (actually CreateFileW) looks at the filename and if it starts with "\." it calls DEVICE_Open(). DEVICE_Open() compares the file name (without the "\." ) against all the entries in VxDList[] and if there is a match it returns a handle based on the appropriate entry in VxDList[].
Let's say I add and entry in VxDList[] like this:
{ "MYDEVICE", 0x1234, NULL, DeviceIo_MyDevice },
If I call CreateFile("\\.\MyDevice0", ...), I will get back a handle based on the entry above. If I call CreateFile("\\.\MyDevice1", ...), I will get back another handle based on the entry above. But, when DeviceIo_MyDevice is called I will not be able to tell if this is the first or the second device.
of course I could add:
{ "MYDEVICE0", 0x1234, NULL, DeviceIo_MyDevice0 }, { "MYDEVICE1", 0x1234, NULL, DeviceIo_MyDevice1 }, . . . { "MYDEVICE256", 0x1234, NULL, DeviceIo_MyDevice256 },
There has to be a better way of doing this. How does this work for, let's say, a USB game controller?
Thanks,
Dan
On Wednesday, December 10, 2003, at 10:22 AM, Rolf Kalbermatter wrote:
Message: 2 Date: Tue, 9 Dec 2003 14:56:16 -0800 Subject: Adding support for a USB device From: Dan Timis timis@museresearch.com To: wine-devel@winehq.org
Hi,
I need help with supporting a particular USB device under wine. I have to start by saying that although I am an experienced C/C++ programmer with some Linux experience, I have almost no Windows or wine experience.
The Windows code for which I need to provide support uses CreateFile() to get a handle to the device. The name of the device is something like "\.\MyDevice0" "\.\MyDevice1" and so on. Then, the code uses DeviceIoControl() to read and write from/to the device. The requirement is not to change the windows code.
I looked through the wine code and I found this in device.c:
static const struct VxDInfo VxDList[]
I could add another entry into the table and write a deviceio handler (BOOL (*deviceio)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);). I wrote some test code in Linux using libusb reading and writing to the device so I know what to do inside the deviceio handler.
Is this the right approach? If so, what do I need to do to get CreateFile to return the right handle?
I think it really depends on the type of device and the possibility to rewrite the device driver or not.
\.\MyDevice0 is just a device driver name which at some point is registered in the registry with the appropriate VXD, SYS, or WDM driver file. If you know the exact DeviceIOControls called into that driver with its parameters and all, you could rewrite the VXD, SYS or WDM driver to call directly the appropriate Unix device driver calls and maybe compile it as a Winelib driver. With a bit hacking in the CreateFile function it should be possible to call such a driver over DeviceIOControl or you could add the according code to the above mentioned VXDList.
Or should I write an external driver that gets loaded by wine? If so, how would I do that? What are the chances that the Windows driver for this device would just work with wine?
If you don't know these details and want to use the original device driver you are probably out of luck. The current CreateFile implementation is not really up to the task of loading an external native device driver and invoke it over the DeviceIOControl (which could probably be remedied with a little hacking at this point) and what is much more problematic there is little or no support for a lot of the Windows kernel services most device driver usually expect to be able to call. When they are not able to link to one or more of those functions at load time, loading of the device driver will simply fail in Wine, as it does with normal DLL files under all Win32 implementations, too.
Rolf Kalbermatter
Dan Timis [mailto:timis@museresearch.com] wrote:
I did some further investigation and it looks like CreateFile (actually CreateFileW) looks at the filename and if it starts with "\." it calls DEVICE_Open(). DEVICE_Open() compares the file name (without the "\." ) against all the entries in VxDList[] and if there is a match it returns a handle based on the appropriate entry in VxDList[].
Let's say I add and entry in VxDList[] like this:
{ "MYDEVICE", 0x1234, NULL, DeviceIo_MyDevice },
If I call CreateFile("\\.\MyDevice0", ...), I will get back a handle based on the entry above. If I call CreateFile("\\.\MyDevice1", ...), I will get back another handle based on the entry above. But, when DeviceIo_MyDevice is called I will not be able to tell if this is the first or the second device.
of course I could add:
{ "MYDEVICE0", 0x1234, NULL, DeviceIo_MyDevice0 }, { "MYDEVICE1", 0x1234, NULL, DeviceIo_MyDevice1 },
. . . { "MYDEVICE256", 0x1234, NULL, DeviceIo_MyDevice256 },
VxDs are really Win95 (and Win3.1 to some extend). They do have a lot of limitations and instantiation of device drivers might be actually one, at least in the way those VxD io controls are implemented in Wine at the moment.
I wouldn't advice to do above mentioned hack as it most certainly never would be accepted into the Wine sources.
There has to be a better way of doing this. How does this work for, let's say, a USB game controller?
Well in real Windows the NtCreateFile function allocates a DriverObject which the DriverEntry function of the device driver can initialize to identify the instance of the driver it refers to. This is then basically the handle returned by the CreateFile function, eventually with a lookup into an internal driver object list or maybe not. The IO Control dispatch function of the driver gets this DriverObject handle as one of its parameters and can therefore refer to the instance data of the driver.
It may be worth looking into the possibility to actually support some basic WDM architecture. This would then have to be done in NtCreateFile which at the moment is a simple stub. This would however require some infrastructure which at the moment is not really present and I'm not sure if it would be necessary to actually add some extra functionality to Wine server itself for this to work as desired, as such device drivers would most probably need to be managed outside of the context of the actual application process. But transfering all such device driver calls to Wine server would probably be quite slow in performance.
I'm also not sure as to how much such an extension would be wishful in the context of Wine itself or if it would unnecessarily complicate the existing Wine architecture. Maybe someone with more insigth into NTDLL and its supposed architecture could explain more here?
Rolf Kalbermatter
I'm also not sure as to how much such an extension would be wishful in the context of Wine itself or if it would unnecessarily complicate the existing Wine architecture. Maybe someone with more insigth into NTDLL and its supposed architecture could explain more here?
I'm currently working on this by moving all device & file handling into ntdll. You'll be able (in the future...) to 1/ define your own new devices 2/ define the link of those devices to real unix devices 3/ handle the NtDeviceIoControlFile messages to the device type you're implementing.
(if everything goes as expected) A+