[5/9] Add support of WDM drivers for USB devices.
Alexander Morozov
amorozov at etersoft.ru
Mon Oct 6 02:20:41 CDT 2008
-------------- next part --------------
From ed6e12ca39e194829ad8d6be4fbd91d9f276d435 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov at etersoft.ru>
Date: Fri, 3 Oct 2008 17:57:00 +0400
Subject: [PATCH] Add support of WDM drivers for USB devices.
---
configure.ac | 14 ++
dlls/wineusbhub/Makefile.in | 15 ++
dlls/wineusbhub/wineusbhub.c | 291 +++++++++++++++++++++++++++++++++++++++
dlls/wineusbhub/wineusbhub.spec | 7 +
programs/winedevice/Makefile.in | 2 +-
programs/winedevice/device.c | 79 +++++++++++-
programs/wineusb/Makefile.in | 15 ++
programs/wineusb/main.c | 224 ++++++++++++++++++++++++++++++
server/device.c | 111 +++++++++++++++
server/protocol.def | 16 ++
tools/wine.inf.in | 10 ++
11 files changed, 782 insertions(+), 2 deletions(-)
create mode 100644 dlls/wineusbhub/Makefile.in
create mode 100644 dlls/wineusbhub/wineusbhub.c
create mode 100644 dlls/wineusbhub/wineusbhub.spec
create mode 100644 programs/wineusb/Makefile.in
create mode 100644 programs/wineusb/main.c
diff --git a/configure.ac b/configure.ac
index 52f5752..7db258e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,7 @@ AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound
AC_ARG_WITH(png, AS_HELP_STRING([--without-png],[do not use PNG]),
[if test "x$withval" = "xno"; then ac_cv_header_png_h=no; fi])
AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)]))
+AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use USB]))
AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]),
[if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi])
AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]),
@@ -332,6 +333,7 @@ AC_CHECK_HEADERS(\
syscall.h \
termios.h \
unistd.h \
+ usb.h \
utime.h \
valgrind/memcheck.h \
valgrind/valgrind.h
@@ -956,6 +958,18 @@ fi
WINE_NOTICE_WITH(sane,[test "x$ac_cv_lib_soname_sane" = "x"],
[libsane development files not found, scanners won't be supported.])
+dnl **** Check for LIBUSB ****
+AC_SUBST(USBLIBS,"")
+if test "$ac_cv_header_usb_h" = "yes"
+then
+ AC_CHECK_LIB(usb, usb_init,
+ [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb library and header])
+ USBLIBS="-lusb"])
+fi
+WINE_NOTICE_WITH(usb,[test "$ac_cv_lib_usb_usb_init" != "yes"],
+ [libusb development files not found, USB won't be supported.])
+
+
dnl **** Check for libgphoto2 ****
AC_CHECK_PROG(gphoto2_devel,gphoto2-config,gphoto2-config,no)
AC_CHECK_PROG(gphoto2port_devel,gphoto2-port-config,gphoto2-port-config,no)
diff --git a/dlls/wineusbhub/Makefile.in b/dlls/wineusbhub/Makefile.in
new file mode 100644
index 0000000..4954a5d
--- /dev/null
+++ b/dlls/wineusbhub/Makefile.in
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR = @srcdir@
+VPATH = @srcdir@
+MODULE = wineusbhub.dll
+IMPORTLIB = wineusbhub
+IMPORTS = ntoskrnl.exe kernel32
+EXTRALIBS = @USBLIBS@
+
+C_SRCS = \
+ wineusbhub.c
+
+ at MAKE_DLL_RULES@
+
+ at DEPENDENCIES@ # everything below this line is overwritten by make depend
diff --git a/dlls/wineusbhub/wineusbhub.c b/dlls/wineusbhub/wineusbhub.c
new file mode 100644
index 0000000..a7985cf
--- /dev/null
+++ b/dlls/wineusbhub/wineusbhub.c
@@ -0,0 +1,291 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+
+#ifdef HAVE_USB_H
+#include <usb.h>
+#endif
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "ddk/ntddk.h"
+#include "ddk/usb.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wineusbhub);
+
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+extern void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost );
+
+DRIVER_OBJECT hubdrv;
+DEVICE_OBJECT *usbdev; /* USB PDO */
+static struct usb_device *dev;
+
+static void add_data( char **dst, int *dst_size, void *src, int src_size )
+{
+ int copy;
+
+ copy = (src_size >= *dst_size) ? *dst_size : src_size;
+ memcpy( *dst, src, copy );
+ *dst += copy;
+ *dst_size -= copy;
+}
+
+void WINAPI __wine_IofCompleteRequest( IRP *irp, UCHAR priority_boost )
+{
+ #ifdef __i386__
+ __asm__( "movl %1,%%edx\n\t"
+ "movl %0,%%ecx\n\t"
+ "call " __ASM_NAME("IofCompleteRequest")
+ : : "g" (irp), "g" (priority_boost) );
+ #else
+ IofCompleteRequest( irp, priority_boost );
+ #endif
+}
+
+NTSTATUS WINAPI __wine_usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
+{
+ IO_STACK_LOCATION *irpsp;
+ URB *urb;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ TRACE( "%p, %p\n", device, irp );
+
+ irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
+ urb = irpsp->Parameters.Others.Argument1;
+
+ switch (urb->u.UrbHeader.Function)
+ {
+ case URB_FUNCTION_SELECT_CONFIGURATION:
+ {
+ USB_CONFIGURATION_DESCRIPTOR *conf_desc =
+ urb->u.UrbSelectConfiguration.ConfigurationDescriptor;
+ usb_dev_handle *husb;
+
+ TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
+
+ husb = usb_open( dev );
+ if (husb)
+ {
+ int ret;
+
+ ret = usb_set_configuration( husb, conf_desc->bConfigurationValue );
+ if (ret < 0)
+ ERR( "%s\n", usb_strerror() );
+ else
+ status = STATUS_SUCCESS;
+ usb_close( husb );
+ }
+ }
+ break;
+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+ {
+ struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
+ &urb->u.UrbControlDescriptorRequest;
+
+ TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
+
+ switch (request->DescriptorType)
+ {
+ case USB_DEVICE_DESCRIPTOR_TYPE:
+ TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
+ if (request->TransferBuffer == NULL)
+ break;
+ if (sizeof(USB_DEVICE_DESCRIPTOR) <= request->TransferBufferLength)
+ {
+ memcpy( request->TransferBuffer, &dev->descriptor,
+ sizeof(USB_DEVICE_DESCRIPTOR) );
+ status = STATUS_SUCCESS;
+ }
+ break;
+ case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+ TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
+ {
+ unsigned int i, k;
+ char *buf = request->TransferBuffer;
+ struct usb_config_descriptor *conf = &dev->config[0];
+ struct usb_interface_descriptor *intf;
+ struct usb_endpoint_descriptor *endp;
+ int size = request->TransferBufferLength;
+
+ /* FIXME: case of num_altsetting > 1 */
+
+ if (buf == NULL)
+ break;
+ add_data( &buf, &size, conf,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR) );
+ if (size > 0 && conf->extra)
+ add_data( &buf, &size, conf->extra, conf->extralen );
+ for (i = 0; i < conf->bNumInterfaces; ++i)
+ {
+ intf = &conf->interface[i].altsetting[0];
+ if (size > 0)
+ add_data( &buf, &size, intf,
+ sizeof(USB_INTERFACE_DESCRIPTOR) );
+ if (size > 0 && intf->extra)
+ add_data( &buf, &size, intf->extra, intf->extralen );
+ for (k = 0; k < intf->bNumEndpoints; ++k)
+ {
+ endp = &intf->endpoint[k];
+ if (size > 0)
+ add_data( &buf, &size, endp,
+ sizeof(USB_ENDPOINT_DESCRIPTOR) );
+ if (size > 0 && endp->extra)
+ add_data( &buf, &size, endp->extra, endp->extralen );
+ }
+ }
+ status = STATUS_SUCCESS;
+ }
+ break;
+ default:
+ FIXME( "unsupported descriptor type %x\n", request->DescriptorType );
+ }
+ }
+ break;
+ case URB_FUNCTION_VENDOR_DEVICE:
+ case URB_FUNCTION_VENDOR_INTERFACE:
+ case URB_FUNCTION_VENDOR_ENDPOINT:
+ {
+ usb_dev_handle *husb;
+ struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
+ &urb->u.UrbControlVendorClassRequest;
+
+ TRACE( "URB_FUNCTION_VENDOR_*\n" );
+
+ husb = usb_open( dev );
+ if (husb)
+ {
+ UCHAR req_type = request->RequestTypeReservedBits | (2 << 5);
+ char *buf;
+ int ret;
+
+ if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_INTERFACE)
+ req_type |= 1;
+ else if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_ENDPOINT)
+ req_type |= 2;
+ buf = HeapAlloc( GetProcessHeap(), 0, request->TransferBufferLength );
+ if (buf != NULL)
+ {
+ memcpy( buf, request->TransferBuffer, request->TransferBufferLength );
+ if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+ req_type |= (1 << 7);
+ ret = usb_control_msg( husb, req_type, request->Request, request->Value,
+ request->Index, buf, request->TransferBufferLength, 1000 );
+ if (ret < 0)
+ ERR( "%s\n", usb_strerror() );
+ else
+ {
+ if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+ {
+ request->TransferBufferLength =
+ (ret <= request->TransferBufferLength) ?
+ ret : request->TransferBufferLength;
+ memcpy( request->TransferBuffer, buf,
+ request->TransferBufferLength );
+ }
+ status = STATUS_SUCCESS;
+ }
+ HeapFree( GetProcessHeap(), 0, buf );
+ }
+ usb_close( husb );
+ }
+ }
+ break;
+ default:
+ FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function );
+ }
+
+ urb->u.UrbHeader.Status = status;
+ if (irp->UserIosb != NULL)
+ {
+ irp->UserIosb->u.Status = status;
+ irp->UserIosb->Information = 0;
+ }
+ irp->IoStatus.u.Status = status;
+ irp->IoStatus.Information = 0;
+ __wine_IofCompleteRequest( irp, IO_NO_INCREMENT );
+
+ return status;
+}
+
+NTSTATUS WINAPI __wine_usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
+{
+ TRACE( "%p, %p\n", device, irp );
+
+ irp->IoStatus.u.Status = STATUS_SUCCESS;
+ irp->IoStatus.Information = 0;
+ __wine_IofCompleteRequest( irp, IO_NO_INCREMENT );
+
+ return STATUS_SUCCESS;
+}
+#endif
+
+DEVICE_OBJECT *__wine_usbhub_get_pdo( UCHAR *pdo_info )
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
+ 'U','S','B','P','D','O','-','%','u',0};
+ static WCHAR bufW[20];
+ UNICODE_STRING pdo_name;
+ struct usb_bus *bus;
+
+ TRACE( "%u, %s, %s\n", pdo_info[0], pdo_info + 1,
+ pdo_info + 2 + strlen( (char *)(pdo_info + 1) ) );
+
+ for (bus = usb_busses; bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next)
+ if (!strcmp( bus->dirname, (char *)(pdo_info + 1) ) &&
+ !strcmp( dev->filename, (char *)(pdo_info + 2 + strlen( bus->dirname )) ))
+ {
+ hubdrv.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __wine_usbhub_internal_ioctl;
+ hubdrv.MajorFunction[IRP_MJ_PNP] = __wine_usbhub_dispatch_pnp;
+
+ snprintfW( bufW, sizeof(bufW), usbpdoW, pdo_info[0] );
+ RtlInitUnicodeString( &pdo_name, bufW );
+
+ if (STATUS_SUCCESS == IoCreateDevice( &hubdrv, 0, &pdo_name, 0, 0, FALSE, &usbdev ))
+ {
+ usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE;
+ return usbdev;
+ }
+ }
+#endif
+ return NULL;
+}
+
+BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv )
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ {
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ }
+#endif
+ return TRUE;
+}
diff --git a/dlls/wineusbhub/wineusbhub.spec b/dlls/wineusbhub/wineusbhub.spec
new file mode 100644
index 0000000..85e5361
--- /dev/null
+++ b/dlls/wineusbhub/wineusbhub.spec
@@ -0,0 +1,7 @@
+##################
+# Wine extensions
+#
+# All functions must be prefixed with '__wine_' (for internal functions)
+# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
+
+@ cdecl __wine_usbhub_get_pdo(ptr)
diff --git a/programs/winedevice/Makefile.in b/programs/winedevice/Makefile.in
index c644b7a..8b8b8dd 100644
--- a/programs/winedevice/Makefile.in
+++ b/programs/winedevice/Makefile.in
@@ -5,7 +5,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = winedevice.exe
APPMODE = -mwindows -municode
-IMPORTS = advapi32 ntoskrnl.exe kernel32 ntdll
+IMPORTS = advapi32 ntoskrnl.exe kernel32 ntdll wineusbhub
C_SRCS = \
device.c
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index 7afe97e..81de49d 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -22,6 +22,10 @@
#include "wine/port.h"
#include <stdarg.h>
+#include <limits.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -31,13 +35,15 @@
#include "winreg.h"
#include "winnls.h"
#include "winsvc.h"
-#include "ddk/wdm.h"
+#include "ddk/ntddk.h"
#include "wine/unicode.h"
+#include "wine/server.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedevice);
WINE_DECLARE_DEBUG_CHANNEL(relay);
+extern DEVICE_OBJECT *__wine_usbhub_get_pdo( UCHAR *pdo_info );
extern NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event );
static WCHAR *driver_name;
@@ -138,6 +144,7 @@ static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname )
WINE_TRACE( "- DriverInit = %p\n", driver_obj.DriverInit );
WINE_TRACE( "- DriverStartIo = %p\n", driver_obj.DriverStartIo );
WINE_TRACE( "- DriverUnload = %p\n", driver_obj.DriverUnload );
+ WINE_TRACE( "- AddDevice = %p\n", driver_extension.AddDevice );
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] );
@@ -268,10 +275,80 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
if (load_driver())
{
+ UNICODE_STRING drvname;
+ NTSTATUS ret = STATUS_SUCCESS;
+ IRP *irp;
+ IO_STACK_LOCATION *irpsp;
+ PDRIVER_DISPATCH dispatch;
+
status.dwCurrentState = SERVICE_RUNNING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
SetServiceStatus( service_handle, &status );
+ RtlInitUnicodeString( &drvname, driver_name );
+
+ if (driver_extension.AddDevice)
+ {
+ NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) =
+ driver_extension.AddDevice;
+ PDEVICE_OBJECT pdev_obj = NULL;
+ UCHAR pdo_info[PATH_MAX + 3];
+ data_size_t reply_size = 0;
+
+ while (!reply_size)
+ SERVER_START_REQ( get_add_device_request )
+ {
+ wine_server_add_data( req, drvname.Buffer, drvname.Length );
+ wine_server_set_reply( req, pdo_info, sizeof(pdo_info) );
+ ret = wine_server_call( req );
+ if (STATUS_SUCCESS == ret)
+ reply_size = wine_server_reply_size( reply );
+ }
+ SERVER_END_REQ;
+
+ pdev_obj = __wine_usbhub_get_pdo( pdo_info );
+ if (pdev_obj)
+ {
+ WINE_TRACE( "calling AddDevice( %p, %p )\n", &driver_obj, pdev_obj );
+ ret = AddDevice( &driver_obj, pdev_obj );
+ if (STATUS_SUCCESS != ret)
+ WINE_ERR( "AddDevice failed: %x\n", ret );
+ }
+ else
+ {
+ ret = STATUS_UNSUCCESSFUL;
+ WINE_ERR( "wineusbhub error\n" );
+ }
+ }
+
+ if (driver_obj.MajorFunction[IRP_MJ_PNP])
+ {
+ irp = IoAllocateIrp( driver_obj.DeviceObject->StackSize, FALSE );
+ if (irp != NULL)
+ {
+ --irp->CurrentLocation;
+ irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation;
+
+ irp->RequestorMode = KernelMode;
+ irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+
+ irpsp->MajorFunction = IRP_MJ_PNP;
+ irpsp->MinorFunction = IRP_MN_START_DEVICE;
+ irpsp->DeviceObject = driver_obj.DeviceObject;
+
+ driver_obj.DeviceObject->CurrentIrp = irp;
+
+ dispatch = driver_obj.MajorFunction[IRP_MJ_PNP];
+ ret = dispatch( driver_obj.DeviceObject, irp );
+ if (STATUS_SUCCESS != ret)
+ WINE_ERR( "MajorFunction[IRP_MJ_PNP] failed: %x\n", ret );
+
+ IoFreeIrp( irp );
+ }
+ else
+ ret = STATUS_UNSUCCESSFUL;
+ }
+
wine_ntoskrnl_main_loop( stop_event );
}
else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) );
diff --git a/programs/wineusb/Makefile.in b/programs/wineusb/Makefile.in
new file mode 100644
index 0000000..d2d0fdf
--- /dev/null
+++ b/programs/wineusb/Makefile.in
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR = @srcdir@
+VPATH = @srcdir@
+MODULE = wineusb.exe
+APPMODE = -mwindows -municode
+IMPORTS = advapi32 ntoskrnl.exe kernel32 ntdll setupapi
+EXTRALIBS = @USBLIBS@
+
+C_SRCS = \
+ main.c
+
+ at MAKE_PROG_RULES@
+
+ at DEPENDENCIES@ # everything below this line is overwritten by make depend
diff --git a/programs/wineusb/main.c b/programs/wineusb/main.c
new file mode 100644
index 0000000..864376d
--- /dev/null
+++ b/programs/wineusb/main.c
@@ -0,0 +1,224 @@
+/*
+ * Service process to call USB driver`s AddDevice routine
+ *
+ * Based on winedevice
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+
+#ifdef HAVE_USB_H
+#include <usb.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "winsvc.h"
+#include "winuser.h"
+#include "setupapi.h"
+#include "ddk/wdm.h"
+#include "ddk/usb.h"
+#include "wine/unicode.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
+
+static WCHAR service_nameW[] = {'w','i','n','e','u','s','b',0};
+static SERVICE_STATUS_HANDLE service_handle;
+static HANDLE stop_event;
+
+static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
+{
+ SERVICE_STATUS status;
+
+ status.dwServiceType = SERVICE_WIN32;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+ status.dwWin32ExitCode = 0;
+ status.dwServiceSpecificExitCode = 0;
+ status.dwCheckPoint = 0;
+ status.dwWaitHint = 0;
+
+ switch(ctrl)
+ {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ WINE_TRACE( "shutting down\n" );
+ status.dwCurrentState = SERVICE_STOP_PENDING;
+ status.dwControlsAccepted = 0;
+ SetServiceStatus( service_handle, &status );
+ SetEvent( stop_event );
+ return NO_ERROR;
+ default:
+ status.dwCurrentState = SERVICE_RUNNING;
+ SetServiceStatus( service_handle, &status );
+ return NO_ERROR;
+ }
+}
+
+static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ HDEVINFO set;
+ GUID guid = {0x36FC9E60, 0xC465, 0x11CF, {0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00}};
+#endif
+ SERVICE_STATUS status;
+
+ WINE_TRACE( "starting service\n" );
+
+ stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
+
+ service_handle = RegisterServiceCtrlHandlerExW( service_nameW, service_handler, NULL );
+ if (!service_handle)
+ return;
+
+ status.dwServiceType = SERVICE_WIN32;
+ status.dwCurrentState = SERVICE_START_PENDING;
+ status.dwControlsAccepted = 0;
+ status.dwWin32ExitCode = 0;
+ status.dwServiceSpecificExitCode = 0;
+ status.dwCheckPoint = 0;
+ status.dwWaitHint = 10000;
+ SetServiceStatus( service_handle, &status );
+
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ set = SetupDiGetClassDevsW( &guid, NULL, 0, 0 );
+ if (set != INVALID_HANDLE_VALUE)
+ {
+ UNICODE_STRING drvname;
+ UCHAR pdo_info[PATH_MAX + 3] = {0};
+ struct usb_device *dev;
+ struct usb_bus *bus;
+ SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
+ DWORD size = 0, i = 0;
+ USHORT vid, pid;
+ char *str;
+ BYTE *buf;
+ BOOL ret;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+ {
+ SetupDiGetDeviceRegistryPropertyA( set, &devInfo, SPDRP_HARDWAREID,
+ NULL, NULL, 0, &size );
+ buf = HeapAlloc( GetProcessHeap(), 0, size );
+ if (buf == NULL)
+ {
+ WINE_ERR( "insufficient memory\n" );
+ continue;
+ }
+ ret = SetupDiGetDeviceRegistryPropertyA( set, &devInfo, SPDRP_HARDWAREID,
+ NULL, buf, size, NULL );
+ if (!ret)
+ {
+ WINE_ERR( "SetupDiGetDeviceRegistryPropertyA failed\n" );
+ HeapFree( GetProcessHeap(), 0, buf );
+ continue;
+ }
+ str = strstr( (char *)buf, "Vid_" );
+ if (str != NULL)
+ {
+ str += 4;
+ vid = strtol( str, NULL, 16 );
+ str = strstr( str, "Pid_" );
+ }
+ if (str == NULL)
+ {
+ WINE_ERR( "bad hardware ID\n" );
+ HeapFree( GetProcessHeap(), 0, buf );
+ continue;
+ }
+ str += 4;
+ pid = strtol( str, NULL, 16 );
+ HeapFree( GetProcessHeap(), 0, buf );
+
+ for (bus = usb_busses; bus && ret; bus = bus->next)
+ for (dev = bus->devices; dev && ret; dev = dev->next)
+ if (dev->descriptor.idVendor == vid &&
+ dev->descriptor.idProduct == pid)
+ {
+ SetupDiGetDeviceRegistryPropertyW( set, &devInfo,
+ SPDRP_SERVICE, NULL, NULL, 0, &size );
+ buf = HeapAlloc( GetProcessHeap(), 0, size );
+ if (buf == NULL)
+ {
+ WINE_ERR( "insufficient memory\n" );
+ ret = FALSE;
+ break;
+ }
+ ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo,
+ SPDRP_SERVICE, NULL, buf, size, NULL );
+ if (!ret)
+ {
+ WINE_ERR( "SetupDiGetDeviceRegistryPropertyW failed\n" );
+ HeapFree( GetProcessHeap(), 0, buf );
+ break;
+ }
+ /* FIXME: check if driver is loaded */
+ RtlInitUnicodeString( &drvname, (PWSTR)buf );
+ strcpy( (char *)(pdo_info + 1), bus->dirname );
+ strcpy( (char *)(pdo_info + 2 + strlen( bus->dirname )), dev->filename );
+
+ SERVER_START_REQ( call_add_device )
+ {
+ req->drvname_len = drvname.Length;
+ wine_server_add_data( req, drvname.Buffer, drvname.Length );
+ wine_server_add_data( req, pdo_info, sizeof(pdo_info) );
+ wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ ++pdo_info[0];
+ HeapFree( GetProcessHeap(), 0, buf );
+ ret = FALSE;
+ break;
+ }
+ }
+ SetupDiDestroyDeviceInfoList( set );
+ }
+ else
+ WINE_ERR( "SetupDiGetClassDevsW failed\n" );
+#endif
+
+ status.dwCurrentState = SERVICE_STOPPED;
+ status.dwControlsAccepted = 0;
+ SetServiceStatus( service_handle, &status );
+ WINE_TRACE( "service stopped\n" );
+}
+
+int wmain( int argc, WCHAR *argv[] )
+{
+ SERVICE_TABLE_ENTRYW service_table[2];
+
+ service_table[0].lpServiceName = service_nameW;
+ service_table[0].lpServiceProc = ServiceMain;
+ service_table[1].lpServiceName = NULL;
+ service_table[1].lpServiceProc = NULL;
+
+ StartServiceCtrlDispatcherW( service_table );
+ return 0;
+}
diff --git a/server/device.c b/server/device.c
index abf0ac5..eb1b593 100644
--- a/server/device.c
+++ b/server/device.c
@@ -32,6 +32,7 @@
#include "file.h"
#include "handle.h"
#include "request.h"
+#include "unicode.h"
struct ioctl_call
{
@@ -160,6 +161,41 @@ static const struct fd_ops device_fd_ops =
};
+static struct list add_dev_requests_list = LIST_INIT(add_dev_requests_list);
+
+struct add_dev_request
+{
+ struct object obj; /* object header */
+ struct unicode_str drvname; /* driver name */
+ void *data; /* driver specific data */
+ data_size_t size; /* driver specific data size */
+ struct list entry; /* entry in add_dev_requests_list */
+};
+
+static void add_dev_req_dump( struct object *obj, int verbose );
+static void add_dev_req_destroy( struct object *obj );
+
+static const struct object_ops add_dev_requests_ops =
+{
+ sizeof(struct add_dev_request), /* size */
+ add_dev_req_dump, /* dump */
+ no_get_type, /* get_type */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ no_satisfied, /* satisfied */
+ no_signal, /* signal */
+ no_get_fd, /* get_fd */
+ no_map_access, /* map_access */
+ default_get_sd, /* get_sd */
+ default_set_sd, /* set_sd */
+ no_lookup_name, /* lookup_name */
+ no_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ add_dev_req_destroy /* destroy */
+};
+
+
static void ioctl_call_dump( struct object *obj, int verbose )
{
struct ioctl_call *ioctl = (struct ioctl_call *)obj;
@@ -425,6 +461,27 @@ static struct device_manager *create_device_manager(void)
}
+static void add_dev_req_dump( struct object *obj, int verbose )
+{
+ struct add_dev_request *add_dev_req = (struct add_dev_request *)obj;
+ struct unicode_str *drvname = &add_dev_req->drvname;
+
+ fprintf( stderr, "AddDevice " );
+ if (drvname)
+ dump_strW( drvname->str, drvname->len / sizeof(WCHAR), stderr, "" );
+ fputc( '\n', stderr );
+}
+
+static void add_dev_req_destroy( struct object *obj )
+{
+ struct add_dev_request *add_dev_req = (struct add_dev_request *)obj;
+
+ list_remove( &add_dev_req->entry );
+ /* data and drvname.str are in the same memory block pointed to by drvname.str */
+ free( (void *)add_dev_req->drvname.str );
+}
+
+
/* create a device manager */
DECL_HANDLER(create_device_manager)
{
@@ -554,3 +611,57 @@ DECL_HANDLER(get_ioctl_result)
}
release_object( device );
}
+
+
+DECL_HANDLER(call_add_device)
+{
+ void *p;
+ struct add_dev_request *add_dev_req;
+ data_size_t size;
+
+ size = get_req_data_size();
+ p = mem_alloc( size );
+ if (p)
+ {
+ add_dev_req = alloc_object( &add_dev_requests_ops );
+ if (add_dev_req)
+ {
+ memcpy( p, get_req_data(), size );
+ add_dev_req->drvname.len = req->drvname_len;
+ add_dev_req->drvname.str = p;
+ add_dev_req->data = (char *)p + req->drvname_len;
+ add_dev_req->size = size - req->drvname_len;
+ list_add_tail( &add_dev_requests_list, &add_dev_req->entry );
+ }
+ else
+ free( p );
+ }
+}
+
+
+DECL_HANDLER(get_add_device_request)
+{
+ struct unicode_str drvname;
+ struct add_dev_request *add_dev_req;
+ int found = 0;
+
+ get_req_unicode_str( &drvname );
+ LIST_FOR_EACH_ENTRY( add_dev_req, &add_dev_requests_list, struct add_dev_request, entry )
+ {
+ struct unicode_str *p = &add_dev_req->drvname;
+
+ if (p->len != drvname.len) continue;
+ if (!strncmpiW( drvname.str, p->str, p->len/sizeof(WCHAR) ))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ {
+ set_reply_data( add_dev_req->data, add_dev_req->size );
+ release_object( add_dev_req );
+ }
+ else
+ set_reply_data( NULL, 0 );
+}
diff --git a/server/protocol.def b/server/protocol.def
index d9fd48c..f0789f2 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3077,3 +3077,19 @@ enum message_type
unsigned int alpha; /* alpha (0..255) */
unsigned int flags; /* LWA_* flags */
@END
+
+
+/* Call AddDevice function in driver */
+ at REQ(call_add_device)
+ data_size_t drvname_len; /* driver name length */
+ VARARG(drvname,unicode_str); /* driver name */
+ VARARG(data,bytes); /* driver specific data */
+ at END
+
+
+/* Check if it should call AddDevice function */
+ at REQ(get_add_device_request)
+ VARARG(drvname,unicode_str); /* driver name */
+ at REPLY
+ VARARG(data,bytes); /* driver specific data */
+ at END
diff --git a/tools/wine.inf.in b/tools/wine.inf.in
index 00e9b97..c952f82 100644
--- a/tools/wine.inf.in
+++ b/tools/wine.inf.in
@@ -78,10 +78,12 @@ AddReg=\
[DefaultInstall.Services]
AddService=MountMgr,0x800,MountMgrService
AddService=Spooler,0,SpoolerService
+AddService=Wineusb,0,WineusbService
[DefaultInstall.NT.Services]
AddService=MountMgr,0x800,MountMgrService
AddService=Spooler,0,SpoolerService
+AddService=Wineusb,0,WineusbService
[Strings]
MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions"
@@ -2709,6 +2711,14 @@ StartType=4
ErrorControl=1
LoadOrderGroup="SpoolerGroup"
+[WineusbService]
+Description="WineUSB"
+DisplayName="WineUSB"
+ServiceBinary="%11%\wineusb.exe"
+ServiceType=0x10
+StartType=2
+ErrorControl=1
+
[Services]
HKLM,"System\CurrentControlSet\Services\VxD\MSTCP",,,""
--
1.5.6.5.GIT
More information about the wine-patches
mailing list