0001 add support of native windows drivers for usb tokens

94
From cb189424b13c5e166bef9acc487c4353c830a10c Mon Sep 17 00:00:00 2001 From: Alexander Morozov <[email protected]> Date: Mon, 25 Jun 2012 16:04:36 +0400 Subject: [PATCH 1/2] Add support of native Windows drivers for USB tokens. --- configure.ac | 41 + dlls/mountmgr.sys/Makefile.in | 8 +- dlls/mountmgr.sys/dbus.c | 15 + dlls/mountmgr.sys/device.c | 4 +- dlls/mountmgr.sys/mountmgr.c | 8 +- dlls/mountmgr.sys/mountmgr.h | 8 + dlls/mountmgr.sys/usbhub.c | 2099 +++++++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/Makefile.in | 1 + dlls/ntoskrnl.exe/ntoskrnl.c | 1462 ++++++++++++++++++++++-- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 46 +- dlls/usbd.sys/usbd.c | 11 + dlls/usbd.sys/usbd.sys.spec | 2 +- include/ddk/ntddk.h | 9 + include/ddk/usb100.h | 10 + include/ddk/usbdlib.h | 1 + include/ddk/usbdrivr.h | 28 + include/ddk/usbioctl.h | 97 ++ include/ddk/usbiodef.h | 35 + include/ddk/wdm.h | 45 +- include/ddk/wdmguid.h | 28 + programs/services/services.c | 21 + programs/winedevice/device.c | 302 ++++- server/device.c | 23 + server/protocol.def | 8 + 24 files changed, 4149 insertions(+), 163 deletions(-) create mode 100644 dlls/mountmgr.sys/usbhub.c create mode 100644 include/ddk/usbdrivr.h create mode 100644 include/ddk/usbioctl.h create mode 100644 include/ddk/usbiodef.h create mode 100644 include/ddk/wdmguid.h diff --git a/configure.ac b/configure.ac index 1753e14..a8f2ae7 100644 --- a/configure.ac +++ b/configure.ac @@ -77,6 +77,8 @@ AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthrea AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanne r support)])) AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF]), [if test "x$withval" = "xno"; then ac_cv_header_tiffio_h=no; fi]) +AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use libudev])) +AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use USB])) AC_ARG_WITH(v4l, AS_HELP_STRING([--without-v4l],[do not use v4l1 (v4l sup port)])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xc omposite extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcom posite_h=no; fi]) @@ -1326,6 +1328,45 @@ fi WINE_NOTICE_WITH(v4l,[test "x$ac_cv_lib_soname_v4l1" = "x"], [libv4l ${notice_platform}development files not found.]) +dnl **** Check for libudev ****

Upload: rafat-touqir-rafsun

Post on 09-Apr-2016

229 views

Category:

Documents


7 download

DESCRIPTION

Native drive

TRANSCRIPT

From cb189424b13c5e166bef9acc487c4353c830a10c Mon Sep 17 00:00:00 2001From: Alexander Morozov <[email protected]>Date: Mon, 25 Jun 2012 16:04:36 +0400Subject: [PATCH 1/2] Add support of native Windows drivers for USB tokens.

--- configure.ac | 41 + dlls/mountmgr.sys/Makefile.in | 8 +- dlls/mountmgr.sys/dbus.c | 15 + dlls/mountmgr.sys/device.c | 4 +- dlls/mountmgr.sys/mountmgr.c | 8 +- dlls/mountmgr.sys/mountmgr.h | 8 + dlls/mountmgr.sys/usbhub.c | 2099 +++++++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/Makefile.in | 1 + dlls/ntoskrnl.exe/ntoskrnl.c | 1462 ++++++++++++++++++++++-- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 46 +- dlls/usbd.sys/usbd.c | 11 + dlls/usbd.sys/usbd.sys.spec | 2 +- include/ddk/ntddk.h | 9 + include/ddk/usb100.h | 10 + include/ddk/usbdlib.h | 1 + include/ddk/usbdrivr.h | 28 + include/ddk/usbioctl.h | 97 ++ include/ddk/usbiodef.h | 35 + include/ddk/wdm.h | 45 +- include/ddk/wdmguid.h | 28 + programs/services/services.c | 21 + programs/winedevice/device.c | 302 ++++- server/device.c | 23 + server/protocol.def | 8 + 24 files changed, 4149 insertions(+), 163 deletions(-) create mode 100644 dlls/mountmgr.sys/usbhub.c create mode 100644 include/ddk/usbdrivr.h create mode 100644 include/ddk/usbioctl.h create mode 100644 include/ddk/usbiodef.h create mode 100644 include/ddk/wdmguid.h

diff --git a/configure.ac b/configure.acindex 1753e14..a8f2ae7 100644--- a/configure.ac+++ b/configure.ac@@ -77,6 +77,8 @@ AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthrea AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)])) AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF]), [if test "x$withval" = "xno"; then ac_cv_header_tiffio_h=no; fi])+AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use libudev]))+AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use USB])) AC_ARG_WITH(v4l, AS_HELP_STRING([--without-v4l],[do not use v4l1 (v4l support)])) 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])@@ -1326,6 +1328,45 @@ fi WINE_NOTICE_WITH(v4l,[test "x$ac_cv_lib_soname_v4l1" = "x"], [libv4l ${notice_platform}development files not found.]) +dnl **** Check for libudev ****

+AC_SUBST(LIBUDEV,"")+if test "x$with_udev" != "xno"+then+ AC_CHECK_HEADER(libudev.h,+ AC_CHECK_LIB(udev, udev_new,+ [AC_DEFINE(HAVE_LIBUDEV, 1, [Define if you have the libudev library and header])+ LIBUDEV="-ludev"]))+fi+WINE_NOTICE_WITH(udev,[test "x$ac_cv_lib_udev_udev_new" = "x"],+ [libudev ${notice_platform}development files not found, no dynamic USB device support.])++dnl **** Check for LIBUSB ****+AC_SUBST(USBLIBS,"")+AC_SUBST(USBINCL,"")+if test "x$with_usb" != "xno"+then+ AC_CHECK_HEADER(usb.h,+ AC_CHECK_LIB(usb, usb_init,+ [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb library and header])+ USBLIBS="-lusb"]))+ ac_save_CPPFLAGS="$CPPFLAGS"+ if test "$PKG_CONFIG" != "false"+ then+ ac_usb_incl="`$PKG_CONFIG --cflags libusb-1.0`"+ ac_usb_libs="`$PKG_CONFIG --libs libusb-1.0`"+ CPPFLAGS="$ac_usb_incl $CPPFLAGS"+ fi+ AC_CHECK_HEADER(libusb.h,+ AC_CHECK_LIB(usb-1.0, libusb_init,+ [AC_DEFINE(HAVE_LIBUSB_1, 1, [Define if you have the libusb-1.0 library and header])+ USBLIBS="$ac_usb_libs"+ USBINCL="$ac_usb_incl"]))+ CPPFLAGS="$ac_save_CPPFLAGS"+fi+WINE_NOTICE_WITH(usb,[test "x$ac_cv_lib_usb_usb_init" != "xyes" -a "x$ac_cv_lib_usb_1_0_libusb_init" != "xyes"],+ [libusb ${notice_platform}development files not found, USB won't be supported.])++ dnl **** Check for libgphoto2 **** if test "x$with_gphoto" != "xno" thendiff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.inindex 3510bec..03f7857 100644--- a/dlls/mountmgr.sys/Makefile.in+++ b/dlls/mountmgr.sys/Makefile.in@@ -1,14 +1,16 @@ MODULE = mountmgr.sys-IMPORTS = uuid advapi32 ntoskrnl.exe+IMPORTS = uuid advapi32 ntoskrnl.exe setupapi DELAYIMPORTS = user32 EXTRADLLFLAGS = -Wb,--subsystem,native EXTRADEFS = @DBUSINCL@ @HALINCL@-EXTRALIBS = @DISKARBITRATIONLIB@+EXTRAINCL = @USBINCL@

+EXTRALIBS = @DISKARBITRATIONLIB@ @USBLIBS@ @LIBUDEV@ C_SRCS = \ dbus.c \ device.c \ diskarb.c \- mountmgr.c+ mountmgr.c \+ usbhub.c @MAKE_DLL_RULES@diff --git a/dlls/mountmgr.sys/dbus.c b/dlls/mountmgr.sys/dbus.cindex ea0341a..d1c490e 100644--- a/dlls/mountmgr.sys/dbus.c+++ b/dlls/mountmgr.sys/dbus.c@@ -575,6 +575,9 @@ static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, v static void hal_new_device( LibHalContext *ctx, const char *udi ) { DBusError error;+#ifndef HAVE_LIBUDEV+ char *subsys = NULL;+#endif char *parent = NULL; char *mount_point = NULL; char *device = NULL;@@ -585,6 +588,12 @@ static void hal_new_device( LibHalContext *ctx, const char *udi ) p_dbus_error_init( &error ); +#ifndef HAVE_LIBUDEV+ if ((subsys = p_libhal_device_get_property_string( ctx, udi, "info.subsystem", NULL )) &&+ !strcmp( subsys, "usb_device" ))+ add_usb_devices();+#endif+ if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error ))) goto done; @@ -615,6 +624,9 @@ static void hal_new_device( LibHalContext *ctx, const char *udi ) else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); done:+#ifndef HAVE_LIBUDEV+ if (subsys) p_libhal_free_string( subsys );+#endif if (type) p_libhal_free_string( type ); if (parent) p_libhal_free_string( parent ); if (device) p_libhal_free_string( device );@@ -630,6 +642,9 @@ static void hal_removed_device( LibHalContext *ctx, const char *udi ) TRACE( "removed %s\n", wine_dbgstr_a(udi) ); +#ifndef HAVE_LIBUDEV

+ remove_usb_devices();+#endif if (!remove_dos_device( -1, udi )) { p_dbus_error_init( &error );diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.cindex 8367cba..3ddf76c 100644--- a/dlls/mountmgr.sys/device.c+++ b/dlls/mountmgr.sys/device.c@@ -887,6 +887,7 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); struct disk_device *dev = device->DeviceExtension;+ NTSTATUS status; TRACE( "ioctl %x insize %u outsize %u\n", irpsp->Parameters.DeviceIoControl.IoControlCode,@@ -965,8 +966,9 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) } LeaveCriticalSection( &device_section );+ status = irp->IoStatus.u.Status; IoCompleteRequest( irp, IO_NO_INCREMENT );- return irp->IoStatus.u.Status;+ return status; } /* driver entry point for the harddisk driver */diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.cindex 927e6e8..c9271ea 100644--- a/dlls/mountmgr.sys/mountmgr.c+++ b/dlls/mountmgr.sys/mountmgr.c@@ -364,6 +364,7 @@ done: static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );+ NTSTATUS status; TRACE( "ioctl %x insize %u outsize %u\n", irpsp->Parameters.DeviceIoControl.IoControlCode,@@ -409,8 +410,9 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp ) irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; break; }+ status = irp->IoStatus.u.Status; IoCompleteRequest( irp, IO_NO_INCREMENT );- return irp->IoStatus.u.Status;+ return status; } /* main entry point for the mount point manager driver */@@ -420,6 +422,7 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) static const WCHAR device_mountmgrW[] = {'\\','D','e','v','i','c','e','\\','M','o','u','n','t','P','o','i','n','t','M','a','n','a','g','e','r',0}; static const WCHAR link_mountmgrW[] = {'\\','?','?','\\','M','o','u','n','t','P','o','i','n','t','M','a','n','a','g','e','r',0};

static const WCHAR harddiskW[] = {'\\','D','r','i','v','e','r','\\','H','a','r','d','d','i','s','k',0};+ static const WCHAR usbhubW[] = {'\\','D','r','i','v','e','r','\\','u','s','b','h','u','b',0}; static const WCHAR devicemapW[] = {'H','A','R','D','W','A','R','E','\\','D','E','V','I','C','E','M','A','P',0}; static const WCHAR parallelW[] = {'P','A','R','A','L','L','E','L',' ','P','O','R','T','S',0}; static const WCHAR serialW[] = {'S','E','R','I','A','L','C','O','M','M',0};@@ -461,6 +464,9 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) RtlInitUnicodeString( &nameW, harddiskW ); status = IoCreateDriver( &nameW, harddisk_driver_entry ); + RtlInitUnicodeString( &nameW, usbhubW );+ status = IoCreateDriver( &nameW, usbhub_driver_entry );+ initialize_dbus(); initialize_diskarbitration(); diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.hindex d1e814f..5ee35f6 100644--- a/dlls/mountmgr.sys/mountmgr.h+++ b/dlls/mountmgr.sys/mountmgr.h@@ -38,6 +38,9 @@ extern void initialize_dbus(void) DECLSPEC_HIDDEN; extern void initialize_diskarbitration(void) DECLSPEC_HIDDEN; +extern NTSTATUS WINAPI usbhub_driver_entry( DRIVER_OBJECT *driver,+ UNICODE_STRING *path ) DECLSPEC_HIDDEN;+ /* device functions */ enum device_type@@ -71,3 +74,8 @@ extern struct mount_point *add_volume_mount_point( DEVICE_OBJECT *device, UNICOD const GUID *guid ) DECLSPEC_HIDDEN; extern void delete_mount_point( struct mount_point *mount ) DECLSPEC_HIDDEN; extern void set_mount_point_id( struct mount_point *mount, const void *id, unsigned int id_len ) DECLSPEC_HIDDEN;++/* usb functions */++extern void add_usb_devices(void) DECLSPEC_HIDDEN;+extern void remove_usb_devices(void) DECLSPEC_HIDDEN;diff --git a/dlls/mountmgr.sys/usbhub.c b/dlls/mountmgr.sys/usbhub.cnew file mode 100644index 0000000..78303b1--- /dev/null+++ b/dlls/mountmgr.sys/usbhub.c@@ -0,0 +1,2099 @@+/*+ * Copyright 2008 - 2011 Alexander Morozov for Etersoft+ *+ * 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 <stdio.h>+#include <stdlib.h>+#ifdef HAVE_POLL_H+#include <poll.h>+#endif+#ifdef HAVE_SYS_POLL_H+#include <sys/poll.h>+#endif++#ifdef HAVE_LIBUSB_1+#include <libusb.h>+#elif defined(HAVE_LIBUSB)+#include <usb.h>+#undef USB_ENDPOINT_TYPE_MASK+#undef USB_ENDPOINT_TYPE_CONTROL+#undef USB_ENDPOINT_TYPE_ISOCHRONOUS+#undef USB_ENDPOINT_TYPE_BULK+#undef USB_ENDPOINT_TYPE_INTERRUPT+#endif+#ifdef HAVE_LIBUDEV+#include <libudev.h>+#endif++#define NONAMELESSUNION+#define NONAMELESSSTRUCT+#define INITGUID++#include "mountmgr.h"+#include "winreg.h"+#include "winsvc.h"+#include "winuser.h"+#include "setupapi.h"+#include "cfgmgr32.h"+#include "devguid.h"+#include "ddk/usbdrivr.h"+#include "ddk/usbioctl.h"+#include "wine/unicode.h"+#include "wine/debug.h"+#include "wine/list.h"++WINE_DEFAULT_DEBUG_CHANNEL(usbhub);++#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)++extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev );

+extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service );+extern NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device );+extern BOOL CDECL __wine_start_service( const WCHAR *name );++#define NUMBER_OF_PORTS 8++static const WCHAR usbW[] = {'U','S','B',0};++static struct list HostControllers = LIST_INIT(HostControllers);+static struct list Devices = LIST_INIT(Devices);++struct HCDInstance+{+ struct list entry;+ DEVICE_OBJECT *dev;+ WCHAR *root_hub_name;+};++struct DeviceInstance+{+ struct list entry;+ USHORT vid;+ USHORT pid;+ char *instance_id;+ WCHAR *service;+ DEVICE_OBJECT *pdo;+#ifdef HAVE_LIBUSB_1+ libusb_device *dev;+#else+ struct usb_device *dev;+#endif+};++struct PdoExtension+{+ struct DeviceInstance *instance;+};++static DRIVER_OBJECT *usbhub_driver;++static CRITICAL_SECTION usbhub_cs;+static CRITICAL_SECTION_DEBUG usbhub_cs_debug =+{+ 0, 0, &usbhub_cs,+ { &usbhub_cs_debug.ProcessLocksList, &usbhub_cs_debug.ProcessLocksList },+ 0, 0, { (DWORD_PTR)(__FILE__ ": usbhub_cs") }+};+static CRITICAL_SECTION usbhub_cs = { &usbhub_cs_debug, -1, 0, 0, 0, 0 };++static BOOL libusb_initialized;++static BOOL device_exists( DEVICE_OBJECT *device )+{+ struct DeviceInstance *instance;++ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ if (instance->pdo == device)+ return TRUE;+ return FALSE;+}

++static struct HCDInstance *get_hcd_instance( DEVICE_OBJECT *device )+{+ struct HCDInstance *instance;++ LIST_FOR_EACH_ENTRY( instance, &HostControllers, struct HCDInstance, entry )+ if (instance->dev == device)+ return instance;+ return NULL;+}++static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size )+{+ int copy;++ copy = (src_size >= *dst_size) ? *dst_size : src_size;+ memcpy( *dst, src, copy );+ *dst += copy;+ *dst_size -= copy;+}++#ifdef HAVE_LIBUSB_1++struct DeviceInstance *get_device_by_index( libusb_device *device,+ ULONG connection_index, ULONG *addr )+{+ struct DeviceInstance *instance;+ uint8_t bus_number = libusb_get_bus_number( device );+ ULONG index = 0;++ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ if (instance->dev && instance->dev != device &&+ libusb_get_bus_number( instance->dev ) == bus_number &&+ ++index == connection_index)+ {+ if (addr)+ *addr = libusb_get_device_address( instance->dev );+ return instance;+ }+ return NULL;+}++#else /* HAVE_LIBUSB_1 */++struct DeviceInstance *get_device_by_index( struct usb_device *device,+ ULONG connection_index, ULONG *addr )+{+ struct DeviceInstance *instance;+ ULONG index = 0;++ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ if (instance->dev && instance->dev != device &&+ instance->dev->bus == device->bus && ++index == connection_index)+ {+ if (addr)+ *addr = instance->dev->devnum;+ return instance;+ }

+ return NULL;+}++#endif /* HAVE_LIBUSB_1 */++static NTSTATUS get_root_hub_name( struct HCDInstance *instance, void *buff,+ ULONG size, ULONG_PTR *outsize )+{+ USB_HCD_DRIVERKEY_NAME *name = buff;+ ULONG name_size;++ if (size < sizeof(*name))+ return STATUS_BUFFER_TOO_SMALL;+ RtlZeroMemory( buff, size );+ name_size = (strlenW(instance->root_hub_name) - 4 + 1) * sizeof(WCHAR);+ name->ActualLength = sizeof(*name) - sizeof(WCHAR) + name_size;+ if (size >= name->ActualLength)+ {+ memcpy( name->DriverKeyName, instance->root_hub_name + 4, name_size );+ *outsize = name->ActualLength;+ }+ else+ *outsize = sizeof(*name);+ return STATUS_SUCCESS;+}++static NTSTATUS get_node_info( void *buff, ULONG size, ULONG_PTR *outsize )+{+ USB_NODE_INFORMATION *node_info = buff;++ if (size < sizeof(*node_info))+ return STATUS_BUFFER_TOO_SMALL;+ RtlZeroMemory( node_info, sizeof(*node_info) );+ node_info->u.HubInformation.HubDescriptor.bDescriptorLength = 9;+ node_info->u.HubInformation.HubDescriptor.bDescriptorType = 41;+ node_info->u.HubInformation.HubDescriptor.bNumberOfPorts = NUMBER_OF_PORTS;+ *outsize = sizeof(*node_info);+ return STATUS_SUCCESS;+}++#ifdef HAVE_LIBUSB_1++static NTSTATUS get_node_conn_info( struct DeviceInstance *inst, void *buff,+ ULONG size, ULONG_PTR *outsize )+{+ USB_NODE_CONNECTION_INFORMATION *conn_info = buff;+ ULONG index = 0;+ struct DeviceInstance *instance;+ uint8_t bus_number = libusb_get_bus_number( inst->dev );+ NTSTATUS status = STATUS_UNSUCCESSFUL;++ if (size < sizeof(*conn_info))+ return STATUS_BUFFER_TOO_SMALL;+ if (!conn_info->ConnectionIndex ||+ conn_info->ConnectionIndex > NUMBER_OF_PORTS)+ return STATUS_INVALID_PARAMETER;+ RtlZeroMemory( (ULONG *)conn_info + 1, sizeof(*conn_info) - sizeof(ULONG) );+ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ {

+ if (instance->dev && instance->dev != inst->dev &&+ libusb_get_bus_number( instance->dev ) == bus_number &&+ ++index == conn_info->ConnectionIndex)+ {+ struct libusb_device_descriptor desc;+ libusb_device_handle *husb;+ int config, ret;++ if (libusb_get_device_descriptor( instance->dev, &desc ))+ break;+ memcpy( &conn_info->DeviceDescriptor, &desc,+ sizeof(USB_DEVICE_DESCRIPTOR) );+ ret = libusb_open( instance->dev, &husb );+ if (!ret)+ {+ ret = libusb_get_configuration( husb, &config );+ if (!ret)+ conn_info->CurrentConfigurationValue = config;+ libusb_close( husb );+ }+ conn_info->ConnectionStatus = 1;+ *outsize = sizeof(*conn_info);+ status = STATUS_SUCCESS;+ break;+ }+ }+ return status;+}++#else /* HAVE_LIBUSB_1 */++static NTSTATUS get_node_conn_info( struct DeviceInstance *inst, void *buff,+ ULONG size, ULONG_PTR *outsize )+{+ USB_NODE_CONNECTION_INFORMATION *conn_info = buff;+ ULONG index = 0;+ struct DeviceInstance *instance;+ NTSTATUS status = STATUS_UNSUCCESSFUL;++ if (size < sizeof(*conn_info))+ return STATUS_BUFFER_TOO_SMALL;+ if (!conn_info->ConnectionIndex ||+ conn_info->ConnectionIndex > NUMBER_OF_PORTS)+ return STATUS_INVALID_PARAMETER;+ RtlZeroMemory( (ULONG *)conn_info + 1, sizeof(*conn_info) - sizeof(ULONG) );+ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ {+ if (instance->dev && instance->dev != inst->dev &&+ instance->dev->bus == inst->dev->bus &&+ ++index == conn_info->ConnectionIndex)+ {+ usb_dev_handle *husb;++ memcpy( &conn_info->DeviceDescriptor, &instance->dev->descriptor,+ sizeof(USB_DEVICE_DESCRIPTOR) );+ husb = usb_open( inst->dev );+ if (husb)+ {+ usb_control_msg( husb, 1 << 7, USB_REQ_GET_CONFIGURATION,

+ 0, 0, (char *)&conn_info->CurrentConfigurationValue,+ sizeof(UCHAR), 0 );+ usb_close( husb );+ }+ conn_info->ConnectionStatus = 1;+ *outsize = sizeof(*conn_info);+ status = STATUS_SUCCESS;+ break;+ }+ }+ return status;+}++#endif /* HAVE_LIBUSB_1 */++static NTSTATUS get_node_conn_driverkey_name( struct DeviceInstance *inst,+ void *buff, ULONG size, ULONG_PTR *outsize )+{+ static const WCHAR device_idW[] = {'U','S','B','\\',+ 'V','i','d','_','%','0','4','x','&',+ 'P','i','d','_','%','0','4','x','\\',0};++ USB_NODE_CONNECTION_DRIVERKEY_NAME *driver_key_name = buff;+ NTSTATUS status = STATUS_UNSUCCESSFUL;+ WCHAR *dev_instance_idW, *bufW;+ struct DeviceInstance *instance;+ HDEVINFO set;+ SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };+ ULONG len, index = 0;++ if (size < sizeof(*driver_key_name))+ return STATUS_BUFFER_TOO_SMALL;+ instance = get_device_by_index( inst->dev,+ driver_key_name->ConnectionIndex, NULL );+ if (instance == NULL)+ return STATUS_INVALID_PARAMETER;+ bufW = HeapAlloc( GetProcessHeap(), 0,+ 2 * MAX_DEVICE_ID_LEN * sizeof(WCHAR) );+ if (bufW == NULL)+ return STATUS_INSUFFICIENT_RESOURCES;+ dev_instance_idW = bufW + MAX_DEVICE_ID_LEN;+ snprintfW( dev_instance_idW, MAX_DEVICE_ID_LEN, device_idW, instance->vid,+ instance->pid );+ len = strlenW(dev_instance_idW);+ RtlMultiByteToUnicodeN( dev_instance_idW + len,+ (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL,+ instance->instance_id, strlen(instance->instance_id) + 1 );+ set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );+ if (set == INVALID_HANDLE_VALUE)+ {+ HeapFree( GetProcessHeap(), 0, bufW );+ return STATUS_UNSUCCESSFUL;+ }+ while (SetupDiEnumDeviceInfo( set, index++, &devInfo ))+ {+ if (!SetupDiGetDeviceInstanceIdW( set, &devInfo, bufW,+ MAX_DEVICE_ID_LEN, NULL ))+ break;+ if (!strcmpiW( dev_instance_idW, bufW ))+ {

+ SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_DRIVER,+ NULL, NULL, 0, &len );+ driver_key_name->ActualLength = 2 * sizeof(ULONG) + len;+ if (size < driver_key_name->ActualLength)+ {+ status = STATUS_SUCCESS;+ *outsize = sizeof(*driver_key_name);+ }+ else if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo,+ SPDRP_DRIVER, NULL, (BYTE *)driver_key_name->DriverKeyName,+ len, NULL ))+ {+ status = STATUS_SUCCESS;+ *outsize = driver_key_name->ActualLength;+ }+ break;+ }+ }+ SetupDiDestroyDeviceInfoList( set );+ HeapFree( GetProcessHeap(), 0, bufW );+ return status;+}++static NTSTATUS WINAPI usbhub_ioctl( DEVICE_OBJECT *device, IRP *irp )+{+ IO_STACK_LOCATION *irpsp;+ NTSTATUS status = STATUS_UNSUCCESSFUL;+ struct DeviceInstance *inst;+ struct HCDInstance *hcd_inst;+ ULONG_PTR info = 0;++ TRACE( "%p, %p\n", device, irp );++ EnterCriticalSection( &usbhub_cs );+ irpsp = IoGetCurrentIrpStackLocation( irp );+ if (device_exists( device ))+ {+ inst = ((struct PdoExtension *)device->DeviceExtension)->instance;+ if (inst->service) goto done;++ switch (irpsp->Parameters.DeviceIoControl.IoControlCode)+ {+ case IOCTL_USB_GET_NODE_INFORMATION:+ status = get_node_info( irp->AssociatedIrp.SystemBuffer,+ irpsp->Parameters.DeviceIoControl.OutputBufferLength, &info );+ break;+ case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:+ status = get_node_conn_info( inst, irp->AssociatedIrp.SystemBuffer,+ irpsp->Parameters.DeviceIoControl.OutputBufferLength, &info );+ break;+ case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:+ status = get_node_conn_driverkey_name( inst,+ irp->AssociatedIrp.SystemBuffer,+ irpsp->Parameters.DeviceIoControl.OutputBufferLength, &info );+ break;+ default:+ FIXME( "IOCTL %08x is not implemented\n",

+ irpsp->Parameters.DeviceIoControl.IoControlCode );+ }+ }+ else if ((hcd_inst = get_hcd_instance( device )))+ {+ switch (irpsp->Parameters.DeviceIoControl.IoControlCode)+ {+ case IOCTL_USB_GET_ROOT_HUB_NAME:+ status = get_root_hub_name( hcd_inst, irp->AssociatedIrp.SystemBuffer,+ irpsp->Parameters.DeviceIoControl.OutputBufferLength, &info );+ break;+ default:+ FIXME( "IOCTL %08x is not implemented for HCD\n",+ irpsp->Parameters.DeviceIoControl.IoControlCode );+ }+ }++done:+ LeaveCriticalSection( &usbhub_cs );+ irp->IoStatus.u.Status = status;+ irp->IoStatus.Information = info;+ IoCompleteRequest( irp, IO_NO_INCREMENT );++ return status;+}++#ifdef HAVE_LIBUSB_1++static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )+{+ IO_STACK_LOCATION *irpsp;+ URB *urb;+ NTSTATUS status = STATUS_UNSUCCESSFUL;+ struct DeviceInstance *inst;++ TRACE( "%p, %p\n", device, irp );++ EnterCriticalSection( &usbhub_cs );+ if (!device_exists( device )) goto done;+ inst = ((struct PdoExtension *)device->DeviceExtension)->instance;+ if (!inst->service) goto done;+ irpsp = IoGetCurrentIrpStackLocation( irp );+ urb = irpsp->Parameters.Others.Argument1;++ switch (irpsp->Parameters.DeviceIoControl.IoControlCode)+ {+ case IOCTL_INTERNAL_USB_SUBMIT_URB:+ switch (urb->u.UrbHeader.Function)+ {+ case URB_FUNCTION_SELECT_CONFIGURATION:+ {+ struct _URB_SELECT_CONFIGURATION *request =+ &urb->u.UrbSelectConfiguration;+ libusb_device_handle *husb;++ TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );++ if (!libusb_open( inst->dev, &husb ))

+ {+ USB_CONFIGURATION_DESCRIPTOR *conf_desc =+ request->ConfigurationDescriptor;+ struct libusb_config_descriptor *conf;+ int ret;++ ret = libusb_set_configuration( husb, (conf_desc != NULL) ?+ conf_desc->bConfigurationValue : -1 );+ if (ret < 0)+ ;+ else if (conf_desc == NULL)+ status = STATUS_SUCCESS;+ else if (!libusb_get_active_config_descriptor( inst->dev, &conf ))+ {+ USBD_INTERFACE_INFORMATION *if_info = &request->Interface;+ const struct libusb_interface_descriptor *intf;+ ULONG k, n;++ /* FIXME: case of num_altsetting > 1 */++ for (n = 0; n < conf_desc->bNumInterfaces; ++n)+ {+ intf = &conf->interface[n].altsetting[0];+ if_info->Class = intf->bInterfaceClass;+ if_info->SubClass = intf->bInterfaceSubClass;+ if_info->Protocol = intf->bInterfaceProtocol;+ if_info->InterfaceHandle =+ (void *)(intf->bInterfaceNumber + 1);+ for (k = 0; k < if_info->NumberOfPipes; ++k)+ {+ if_info->Pipes[k].MaximumPacketSize =+ intf->endpoint[k].wMaxPacketSize;+ if_info->Pipes[k].EndpointAddress =+ intf->endpoint[k].bEndpointAddress;+ if_info->Pipes[k].Interval =+ intf->endpoint[k].bInterval;+ if_info->Pipes[k].PipeType =+ intf->endpoint[k].bmAttributes & 3;+ if_info->Pipes[k].PipeHandle =+ (void *)(intf->endpoint[k].bEndpointAddress ++ ((intf->bInterfaceNumber + 1) << 8));+ }+ if_info = (USBD_INTERFACE_INFORMATION *)+ ((char *)if_info + if_info->Length);+ }+ libusb_free_config_descriptor( conf );+ status = STATUS_SUCCESS;+ }+ libusb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_SELECT_INTERFACE:+ {+ struct _URB_SELECT_INTERFACE *request =+ &urb->u.UrbSelectInterface;+ libusb_device_handle *husb;

++ TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" );++ if (!libusb_open( inst->dev, &husb ))+ {+ int ret;++ ret = libusb_claim_interface( husb,+ request->Interface.InterfaceNumber );+ if (!ret)+ {+ ret = libusb_set_interface_alt_setting( husb,+ request->Interface.InterfaceNumber,+ request->Interface.AlternateSetting );+ if (!libusb_release_interface( husb,+ request->Interface.InterfaceNumber ) && !ret)+ status = STATUS_SUCCESS;+ }+ libusb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:+ {+ struct _URB_BULK_OR_INTERRUPT_TRANSFER *request =+ &urb->u.UrbBulkOrInterruptTransfer;+ unsigned char *buf = request->TransferBuffer;+ libusb_device_handle *husb;++ TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" );++ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (!libusb_open( inst->dev, &husb ))+ {+ int ret, transferred;++ ret = libusb_claim_interface( husb,+ ((int)request->PipeHandle >> 8) - 1 );+ if (!ret)+ {+ /* FIXME: add support for an interrupt transfer */+ ret = libusb_bulk_transfer( husb,+ (unsigned int)request->PipeHandle,+ buf, request->TransferBufferLength,+ &transferred, 0 );+ if (!libusb_release_interface( husb,+ ((int)request->PipeHandle >> 8) - 1 ) && !ret)+ {+ request->TransferBufferLength = transferred;+ status = STATUS_SUCCESS;+ }+ }+ libusb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:+ {+ struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =

+ &urb->u.UrbControlDescriptorRequest;+ ULONG size = request->TransferBufferLength;+ unsigned char *buf = request->TransferBuffer;++ TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );++ if (!size)+ {+ status = STATUS_SUCCESS;+ break;+ }+ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (buf == NULL)+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }++ switch (request->DescriptorType)+ {+ case USB_DEVICE_DESCRIPTOR_TYPE:+ TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );+ {+ struct libusb_device_descriptor desc;++ if (libusb_get_device_descriptor( inst->dev, &desc ))+ break;+ memcpy( buf, &desc, (size < sizeof(USB_DEVICE_DESCRIPTOR)) ?+ size : sizeof(USB_DEVICE_DESCRIPTOR) );+ status = STATUS_SUCCESS;+ }+ break;+ case USB_CONFIGURATION_DESCRIPTOR_TYPE:+ TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );+ {+ unsigned int i, k;+ struct libusb_config_descriptor *conf;+ const struct libusb_interface_descriptor *intf;+ const struct libusb_endpoint_descriptor *endp;++ /* FIXME: case of num_altsetting > 1 */++ if (libusb_get_active_config_descriptor( inst->dev, &conf ))+ break;+ add_data( &buf, &size, conf,+ sizeof(USB_CONFIGURATION_DESCRIPTOR) );+ if (size > 0 && conf->extra)+ add_data( &buf, &size, conf->extra, conf->extra_length );+ 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->extra

_length );+ 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->extra_length );+ }+ }+ libusb_free_config_descriptor( conf );+ status = STATUS_SUCCESS;+ }+ break;+ case USB_STRING_DESCRIPTOR_TYPE:+ TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" );+ {+ libusb_device_handle *husb;+ int ret;++ if (!libusb_open( inst->dev, &husb ))+ {+ ret = libusb_get_string_descriptor( husb, request->Index,+ request->LanguageId, buf, size );+ libusb_close( husb );+ if (ret < 0) break;+ status = STATUS_SUCCESS;+ }+ }+ }+ }+ break;+ case URB_FUNCTION_GET_STATUS_FROM_DEVICE:+ {+ struct _URB_CONTROL_GET_STATUS_REQUEST *request =+ &urb->u.UrbControlGetStatusRequest;+ void *buf = request->TransferBuffer;+ libusb_device_handle *husb;+ int ret;++ TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" );++ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (buf == NULL || request->TransferBufferLength < sizeof(USHORT))+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }+ if (!libusb_open( inst->dev, &husb ))+ {+ ret = libusb_control_transfer( husb, 1 << 7,+ LIBUSB_REQUEST_GET_STATUS, 0, request->Index, buf,+ sizeof(USHORT), 0 );+ libusb_close( husb );+ if (ret < 0) break;

+ status = STATUS_SUCCESS;+ }+ }+ break;+ case URB_FUNCTION_VENDOR_DEVICE:+ case URB_FUNCTION_VENDOR_INTERFACE:+ case URB_FUNCTION_VENDOR_ENDPOINT:+ case URB_FUNCTION_CLASS_DEVICE:+ case URB_FUNCTION_CLASS_INTERFACE:+ case URB_FUNCTION_CLASS_ENDPOINT:+ {+ libusb_device_handle *husb;+ struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =+ &urb->u.UrbControlVendorClassRequest;+ unsigned char *req_buf = request->TransferBuffer;+ ULONG size = request->TransferBufferLength;++ TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" );++ if (req_buf == NULL && request->TransferBufferMDL != NULL)+ req_buf = request->TransferBufferMDL->MappedSystemVa;+ if (size && req_buf == NULL)+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }+ if (!libusb_open( inst->dev, &husb ))+ {+ UCHAR req_type = request->RequestTypeReservedBits;+ unsigned char *buf;+ int ret;++ switch (urb->u.UrbHeader.Function)+ {+ case URB_FUNCTION_VENDOR_DEVICE: req_type |= 0x40; break;+ case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break;+ case URB_FUNCTION_VENDOR_ENDPOINT: req_type |= 0x42; break;+ case URB_FUNCTION_CLASS_DEVICE: req_type |= 0x20; break;+ case URB_FUNCTION_CLASS_INTERFACE: req_type |= 0x21; break;+ case URB_FUNCTION_CLASS_ENDPOINT: req_type |= 0x22; break;+ }+ buf = HeapAlloc( GetProcessHeap(), 0, size );+ if (buf != NULL)+ {+ memcpy( buf, req_buf, size );+ if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)+ req_type |= (1 << 7);+ ret = libusb_control_transfer( husb, req_type,+ request->Request, request->Value, request->Index,+ buf, size, 0 );+ if (ret >= 0)+ {

+ if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)+ {+ request->TransferBufferLength =+ (ret < size) ? ret : size;+ memcpy( req_buf, buf, request->TransferBufferLength );+ }+ status = STATUS_SUCCESS;+ }+ HeapFree( GetProcessHeap(), 0, buf );+ }+ libusb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_GET_CONFIGURATION:+ {+ struct _URB_CONTROL_GET_CONFIGURATION_REQUEST *request =+ &urb->u.UrbControlGetConfigurationRequest;+ char *buf = request->TransferBuffer;+ libusb_device_handle *husb;+ int ret, config;++ TRACE( "URB_FUNCTION_GET_CONFIGURATION\n" );++ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (buf == NULL || request->TransferBufferLength < 1)+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }+ if (!libusb_open( inst->dev, &husb ))+ {+ ret = libusb_get_configuration( husb, &config );+ libusb_close( husb );+ if (ret < 0) break;+ *buf = config;+ status = STATUS_SUCCESS;+ }+ }+ break;+ default:+ FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function );+ }+ urb->u.UrbHeader.Status = status;+ break;+ default:+ FIXME( "IOCTL %08x is not implemented\n",+ irpsp->Parameters.DeviceIoControl.IoControlCode );+ }++done:+ LeaveCriticalSection( &usbhub_cs );+ irp->IoStatus.u.Status = status;+ irp->IoStatus.Information = 0;+ IoCompleteRequest( irp, IO_NO_INCREMENT );+

+ return status;+}++#else /* HAVE_LIBUSB_1 */++static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )+{+ IO_STACK_LOCATION *irpsp;+ URB *urb;+ NTSTATUS status = STATUS_UNSUCCESSFUL;+ struct DeviceInstance *inst;++ TRACE( "%p, %p\n", device, irp );++ EnterCriticalSection( &usbhub_cs );+ if (!device_exists( device )) goto done;+ inst = ((struct PdoExtension *)device->DeviceExtension)->instance;+ if (!inst->service) goto done;+ irpsp = IoGetCurrentIrpStackLocation( irp );+ urb = irpsp->Parameters.Others.Argument1;++ switch (irpsp->Parameters.DeviceIoControl.IoControlCode)+ {+ case IOCTL_INTERNAL_USB_SUBMIT_URB:+ switch (urb->u.UrbHeader.Function)+ {+ case URB_FUNCTION_SELECT_CONFIGURATION:+ {+ struct _URB_SELECT_CONFIGURATION *request =+ &urb->u.UrbSelectConfiguration;+ usb_dev_handle *husb;++ TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );++ husb = usb_open( inst->dev );+ if (husb)+ {+ USB_CONFIGURATION_DESCRIPTOR *conf_desc =+ urb->u.UrbSelectConfiguration.ConfigurationDescriptor;+ int ret;++ ret = usb_set_configuration( husb, (conf_desc != NULL) ?+ conf_desc->bConfigurationValue : -1 );+ if (ret < 0)+ ;+ else if (conf_desc == NULL)+ status = STATUS_SUCCESS;+ else+ {+ USBD_INTERFACE_INFORMATION *if_info = &request->Interface;+ struct usb_config_descriptor *conf;+ struct usb_interface_descriptor *intf;+ ULONG k, n;++ /* FIXME: case of num_altsetting > 1 */++ for (n = 0; n < inst->dev->descriptor.bNumConfigurations; ++n)

+ if (inst->dev->config[n].bConfigurationValue ==+ conf_desc->bConfigurationValue)+ {+ conf = &inst->dev->config[n];+ break;+ }+ for (n = 0; n < conf_desc->bNumInterfaces; ++n)+ {+ intf = &conf->interface[n].altsetting[0];+ if_info->Class = intf->bInterfaceClass;+ if_info->SubClass = intf->bInterfaceSubClass;+ if_info->Protocol = intf->bInterfaceProtocol;+ if_info->InterfaceHandle =+ (void *)(intf->bInterfaceNumber + 1);+ for (k = 0; k < if_info->NumberOfPipes; ++k)+ {+ if_info->Pipes[k].MaximumPacketSize =+ intf->endpoint[k].wMaxPacketSize;+ if_info->Pipes[k].EndpointAddress =+ intf->endpoint[k].bEndpointAddress;+ if_info->Pipes[k].Interval =+ intf->endpoint[k].bInterval;+ if_info->Pipes[k].PipeType =+ intf->endpoint[k].bmAttributes & 3;+ if_info->Pipes[k].PipeHandle =+ (void *)(intf->endpoint[k].bEndpointAddress ++ ((intf->bInterfaceNumber + 1) << 8));+ }+ if_info = (USBD_INTERFACE_INFORMATION *)+ ((char *)if_info + if_info->Length);+ }+ status = STATUS_SUCCESS;+ }+ usb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_SELECT_INTERFACE:+ {+ struct _URB_SELECT_INTERFACE *request =+ &urb->u.UrbSelectInterface;+ usb_dev_handle *husb;++ TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" );++ husb = usb_open( inst->dev );+ if (husb)+ {+ int ret;++ ret = usb_claim_interface( husb,+ request->Interface.InterfaceNumber );+ if (!ret)+ {+ ret = usb_set_altinterface( husb,+ request->Interface.AlternateSetting );+ if (!usb_release_interface( husb,+ request->Interface.InterfaceNumber ) && !ret)+ status = STATUS_SUCCESS;

+ }+ usb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:+ {+ struct _URB_BULK_OR_INTERRUPT_TRANSFER *request =+ &urb->u.UrbBulkOrInterruptTransfer;+ char *buf = request->TransferBuffer;+ usb_dev_handle *husb;++ TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" );++ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ husb = usb_open( inst->dev );+ if (husb)+ {+ int ret;++ ret = usb_claim_interface( husb,+ ((int)request->PipeHandle >> 8) - 1 );+ if (!ret)+ {+ /* FIXME: add support for an interrupt transfer */+ if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)+ ret = usb_bulk_read( husb, (int)request->PipeHandle & 0xff,+ buf, request->TransferBufferLength, 0 );+ else+ ret = usb_bulk_write( husb, (int)request->PipeHandle & 0xff,+ buf, request->TransferBufferLength, 0 );+ if (!usb_release_interface( husb,+ ((int)request->PipeHandle >> 8) - 1 ) && ret >= 0)+ {+ request->TransferBufferLength = ret;+ status = STATUS_SUCCESS;+ }+ }+ usb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:+ {+ struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =+ &urb->u.UrbControlDescriptorRequest;+ ULONG size = request->TransferBufferLength;+ unsigned char *buf = request->TransferBuffer;++ TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );++ if (!size)+ {+ status = STATUS_SUCCESS;+ break;

+ }+ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (buf == NULL)+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }++ switch (request->DescriptorType)+ {+ case USB_DEVICE_DESCRIPTOR_TYPE:+ TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );+ memcpy( buf, &inst->dev->descriptor,+ (size < sizeof(USB_DEVICE_DESCRIPTOR)) ?+ size : sizeof(USB_DEVICE_DESCRIPTOR) );+ status = STATUS_SUCCESS;+ break;+ case USB_CONFIGURATION_DESCRIPTOR_TYPE:+ TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );+ {+ unsigned int i, k;+ struct usb_config_descriptor *conf = &inst->dev->config[0];+ struct usb_interface_descriptor *intf;+ struct usb_endpoint_descriptor *endp;++ /* FIXME: case of num_altsetting > 1 */++ 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;+ case USB_STRING_DESCRIPTOR_TYPE:+ TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" );+ {

+ usb_dev_handle *husb;+ int ret;++ husb = usb_open( inst->dev );+ if (husb)+ {+ ret = usb_get_string( husb, request->Index,+ request->LanguageId, (void *)buf, size );+ if (ret >= 0)+ status = STATUS_SUCCESS;+ usb_close( husb );+ }+ }+ }+ }+ break;+ case URB_FUNCTION_GET_STATUS_FROM_DEVICE:+ {+ struct _URB_CONTROL_GET_STATUS_REQUEST *request =+ &urb->u.UrbControlGetStatusRequest;+ void *buf = request->TransferBuffer;+ usb_dev_handle *husb;+ int ret;++ TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" );++ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (buf == NULL || request->TransferBufferLength < sizeof(USHORT))+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }+ husb = usb_open( inst->dev );+ if (husb)+ {+ ret = usb_control_msg( husb, 1 << 7, USB_REQ_GET_STATUS, 0,+ request->Index, buf, sizeof(USHORT), 0 );+ if (ret >= 0)+ status = STATUS_SUCCESS;+ usb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_VENDOR_DEVICE:+ case URB_FUNCTION_VENDOR_INTERFACE:+ case URB_FUNCTION_VENDOR_ENDPOINT:+ case URB_FUNCTION_CLASS_DEVICE:+ case URB_FUNCTION_CLASS_INTERFACE:+ case URB_FUNCTION_CLASS_ENDPOINT:+ {+ usb_dev_handle *husb;+ struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =+ &urb->u.UrbControlVendorClassRequest;+ unsigned char *req_buf = request->TransferBuffer;+ ULONG size = request->TransferBufferLength;++ TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" );+

+ if (req_buf == NULL && request->TransferBufferMDL != NULL)+ req_buf = request->TransferBufferMDL->MappedSystemVa;+ if (size && req_buf == NULL)+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }+ husb = usb_open( inst->dev );+ if (husb)+ {+ UCHAR req_type = request->RequestTypeReservedBits;+ char *buf;+ int ret;++ switch (urb->u.UrbHeader.Function)+ {+ case URB_FUNCTION_VENDOR_DEVICE: req_type |= 0x40; break;+ case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break;+ case URB_FUNCTION_VENDOR_ENDPOINT: req_type |= 0x42; break;+ case URB_FUNCTION_CLASS_DEVICE: req_type |= 0x20; break;+ case URB_FUNCTION_CLASS_INTERFACE: req_type |= 0x21; break;+ case URB_FUNCTION_CLASS_ENDPOINT: req_type |= 0x22; break;+ }+ buf = HeapAlloc( GetProcessHeap(), 0, size );+ if (buf != NULL)+ {+ memcpy( buf, req_buf, size );+ 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, size, 0 );+ if (ret >= 0)+ {+ if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)+ {+ request->TransferBufferLength =+ (ret < size) ? ret : size;+ memcpy( req_buf, buf, request->TransferBufferLength );+ }+ status = STATUS_SUCCESS;+ }+ HeapFree( GetProcessHeap(), 0, buf );+ }+ usb_close( husb );+ }+ }+ break;+ case URB_FUNCTION_GET_CONFIGURATION:+ {+ struct _URB_CONTROL_GET_CONFIGURATION_REQUEST *request =

+ &urb->u.UrbControlGetConfigurationRequest;+ char *buf = request->TransferBuffer;+ usb_dev_handle *husb;+ int ret;++ TRACE( "URB_FUNCTION_GET_CONFIGURATION\n" );++ if (buf == NULL && request->TransferBufferMDL != NULL)+ buf = request->TransferBufferMDL->MappedSystemVa;+ if (buf == NULL || request->TransferBufferLength < 1)+ {+ status = STATUS_INVALID_PARAMETER;+ break;+ }+ husb = usb_open( inst->dev );+ if (husb)+ {+ ret = usb_control_msg( husb, 1 << 7,+ USB_REQ_GET_CONFIGURATION, 0, 0, buf, 1, 0 );+ if (ret >= 0)+ status = STATUS_SUCCESS;+ usb_close( husb );+ }+ }+ break;+ default:+ FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function );+ }+ urb->u.UrbHeader.Status = status;+ break;+ default:+ FIXME( "IOCTL %08x is not implemented\n",+ irpsp->Parameters.DeviceIoControl.IoControlCode );+ }++done:+ LeaveCriticalSection( &usbhub_cs );+ irp->IoStatus.u.Status = status;+ irp->IoStatus.Information = 0;+ IoCompleteRequest( irp, IO_NO_INCREMENT );++ return status;+}++#endif /* HAVE_LIBUSB_1 */++static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )+{+ static const WCHAR device_idW[] = {'U','S','B','\\',+ 'V','i','d','_','%','0','4','x','&',+ 'P','i','d','_','%','0','4','x',0};+ static const WCHAR root_hub_idW[] = {'U','S','B','\\',+ 'R','O','O','T','_','H','U','B',0};++ struct PdoExtension *dx;+ IO_STACK_LOCATION *irpsp;+ NTSTATUS status = STATUS_UNSUCCESSFUL;+ ULONG_PTR info = 0;+

+ TRACE( "%p, %p\n", device, irp );++ EnterCriticalSection( &usbhub_cs );+ irpsp = IoGetCurrentIrpStackLocation( irp );+ if (!device_exists( device ))+ {+ if (irpsp->MinorFunction == IRP_MN_SURPRISE_REMOVAL ||+ irpsp->MinorFunction == IRP_MN_REMOVE_DEVICE)+ status = STATUS_SUCCESS;+ goto done;+ }+ dx = device->DeviceExtension;+ switch (irpsp->MinorFunction)+ {+ case IRP_MN_QUERY_DEVICE_RELATIONS:+ /* dx->instance->service is NULL for root hubs */+ if (dx->instance->service)+ {+ status = irp->IoStatus.u.Status;+ info = irp->IoStatus.Information;+ }+ else+ {+ FIXME( "IRP_MN_QUERY_DEVICE_RELATIONS is not implemented for root hubs\n" );+ status = STATUS_NOT_IMPLEMENTED;+ }+ break;+ case IRP_MN_QUERY_ID:+ switch (irpsp->Parameters.QueryId.IdType)+ {+ case BusQueryDeviceID:+ {+ WCHAR *device_id = ExAllocatePool( PagedPool, dx->instance->service ?+ sizeof(device_idW) : sizeof(root_hub_idW) );++ if (device_id == NULL)+ {+ status = STATUS_INSUFFICIENT_RESOURCES;+ break;+ }+ if (dx->instance->service)+ snprintfW( device_id, strlenW(device_idW) + 1, device_idW,+ dx->instance->vid, dx->instance->pid );+ else+ strcpyW( device_id, root_hub_idW );+ status = STATUS_SUCCESS;+ info = (ULONG_PTR)device_id;+ break;+ }+ case BusQueryInstanceID:+ {+ char *instance_id;+ ULONG len;+ ULONG size;+ WCHAR *instance_idW;++ instance_id = strrchr( dx->instance->instance_id, '&' );+ instance_id = instance_id ? (instance_id + 1) : dx->instance->insta

nce_id;+ len = strlen(instance_id) + 1;+ size = len * sizeof(WCHAR);+ instance_idW = ExAllocatePool( PagedPool, size );+ if (instance_idW == NULL)+ {+ status = STATUS_INSUFFICIENT_RESOURCES;+ break;+ }+ RtlMultiByteToUnicodeN( instance_idW, size, NULL, instance_id, len );+ status = STATUS_SUCCESS;+ info = (ULONG_PTR)instance_idW;+ break;+ }+ default:+ FIXME( "IRP_MN_QUERY_ID: IdType %u is not implemented\n",+ irpsp->Parameters.QueryId.IdType );+ status = STATUS_NOT_IMPLEMENTED;+ }+ break;+ default:+ status = STATUS_SUCCESS;+ }++done:+ LeaveCriticalSection( &usbhub_cs );+ irp->IoStatus.u.Status = status;+ irp->IoStatus.Information = info;+ IoCompleteRequest( irp, IO_NO_INCREMENT );++ return status;+}++static void stop_service( const WCHAR *name )+{+ SC_HANDLE scm, service;+ SERVICE_STATUS ss;++ scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );+ if (scm == NULL)+ return;++ service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );+ if (service == NULL)+ {+ CloseServiceHandle( scm );+ return;+ }++ ControlService( service, SERVICE_CONTROL_STOP, &ss );++ CloseServiceHandle( service );+ CloseServiceHandle( scm );+}++static BOOL create_pdo_name( UNICODE_STRING *pdo_name )+{+ static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',+ 'U','S','B','P','D','O','-','%','u',0};

++ static unsigned int last_pdo_num;+ WCHAR *buf = RtlAllocateHeap( GetProcessHeap(), 0, 30 * sizeof(WCHAR) );++ if (buf == NULL) return FALSE;+ snprintfW( buf, 30, usbpdoW, last_pdo_num++ );+ RtlInitUnicodeString( pdo_name, buf );+ return TRUE;+}++static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst,+ DRIVER_OBJECT *hubdrv, ULONG flags )+{+ UNICODE_STRING pdo_name;+ DEVICE_OBJECT *usbdev = NULL;++ if (!create_pdo_name( &pdo_name )) return NULL;+ if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name,+ 0, 0, FALSE, &usbdev ) == STATUS_SUCCESS)+ {+ ((struct PdoExtension *)usbdev->DeviceExtension)->instance = inst;+ usbdev->Flags |= flags;+ usbdev->Flags &= ~DO_DEVICE_INITIALIZING;+ }+ RtlFreeUnicodeString( &pdo_name );+ return usbdev;+}++static BOOL register_root_hub_device( DEVICE_OBJECT *dev,+ unsigned int instance_id, UNICODE_STRING *link )+{+ static const WCHAR root_hub_idW[] = {'U','S','B',+ '\\','R','O','O','T','_','H','U','B',+ '\\','%','u',0};++ HDEVINFO set;+ SP_DEVINFO_DATA devInfo;+ WCHAR *devnameW;+ ULONG size;+ BOOL ret;+ NTSTATUS status = STATUS_UNSUCCESSFUL;++ size = sizeof(root_hub_idW) + 16 * sizeof(WCHAR);+ devnameW = HeapAlloc( GetProcessHeap(), 0, size );+ if (devnameW == NULL) return FALSE;+ snprintfW( devnameW, size / sizeof(WCHAR), root_hub_idW, instance_id );++ set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );+ if (set == INVALID_HANDLE_VALUE) goto done;+ devInfo.cbSize = sizeof(SP_DEVINFO_DATA);+ ret = SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB,+ NULL, NULL, 0, &devInfo );+ if (ret)+ {+ ret = SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL );+ if (!ret) goto done;+ }+ else if (ERROR_DEVINST_ALREADY_EXISTS != GetLastError()) goto done;++ status = IoRegisterDeviceInterface( dev, &GUID_DEVINTERFACE_USB_HUB,

+ NULL, link );+ if (status == STATUS_SUCCESS)+ IoSetDeviceInterfaceState( link, TRUE );+done:+ if (set != INVALID_HANDLE_VALUE)+ SetupDiDestroyDeviceInfoList( set );+ HeapFree( GetProcessHeap(), 0, devnameW );+ return (status == STATUS_SUCCESS) ? TRUE : FALSE;+}++static void create_hcd_device( unsigned int instance_id, DRIVER_OBJECT *hubdrv,+ UNICODE_STRING *link )+{+ static const WCHAR usbfdoW[] = {'\\','D','e','v','i','c','e',+ '\\','U','S','B','F','D','O','-','%','u',0};+ static const WCHAR usbhcdW[] = {'\\','D','o','s','D','e','v','i','c','e','s',+ '\\','H','C','D','%','u',0};++ WCHAR *fdo_buf = RtlAllocateHeap( GetProcessHeap(), 0, 30 * sizeof(WCHAR) );+ WCHAR *hcd_buf = RtlAllocateHeap( GetProcessHeap(), 0, 30 * sizeof(WCHAR) );+ UNICODE_STRING fdo_name, hcd_name;+ struct HCDInstance *instance = NULL;+ NTSTATUS status = STATUS_UNSUCCESSFUL;++ if (fdo_buf == NULL || hcd_buf == NULL) goto done;+ instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );+ if (instance == NULL) goto done;+ instance->root_hub_name = HeapAlloc( GetProcessHeap(), 0,+ link->Length + sizeof(WCHAR) );+ if (instance->root_hub_name == NULL) goto done;+ memcpy( instance->root_hub_name, link->Buffer, link->Length );+ instance->root_hub_name[link->Length / sizeof(WCHAR)] = 0;++ snprintfW( fdo_buf, 30, usbfdoW, instance_id );+ RtlInitUnicodeString( &fdo_name, fdo_buf );+ snprintfW( hcd_buf, 30, usbhcdW, instance_id );+ RtlInitUnicodeString( &hcd_name, hcd_buf );++ status = IoCreateDevice( hubdrv, 0, &fdo_name, 0, 0, FALSE, &instance->dev );+ if (status != STATUS_SUCCESS) goto done;+ IoCreateSymbolicLink( &hcd_name, &fdo_name );+ instance->dev->Flags &= ~DO_DEVICE_INITIALIZING;+ list_add_tail( &HostControllers, &instance->entry );+done:+ if (status != STATUS_SUCCESS && instance != NULL)+ {+ HeapFree( GetProcessHeap(), 0, instance->root_hub_name );+ HeapFree( GetProcessHeap(), 0, instance );+ }+ RtlFreeUnicodeString( &fdo_name );+ RtlFreeUnicodeString( &hcd_name );+}++static void create_root_hub_device( USHORT vid, USHORT pid, void *dev,+ DRIVER_OBJECT *hubdrv )

+{+ static unsigned int instance_id;+ struct DeviceInstance *instance = NULL;+ UNICODE_STRING link;++ instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );+ if (instance == NULL) return;+ instance->instance_id = HeapAlloc( GetProcessHeap(), 0, 16 );+ if (instance->instance_id == NULL) goto fail;+ instance->vid = vid;+ instance->pid = pid;+ snprintf( instance->instance_id, 16, "%u", instance_id );+ instance->service = NULL;+ instance->dev = dev;++ instance->pdo = create_pdo( instance, hubdrv, DO_POWER_PAGABLE );+ if (instance->pdo == NULL) goto fail;+ list_add_tail( &Devices, &instance->entry );+ if (register_root_hub_device( instance->pdo, instance_id, &link ))+ {+ create_hcd_device( instance_id, hubdrv, &link );+ RtlFreeUnicodeString( &link );+ }+ ++instance_id;+ return;+fail:+ HeapFree( GetProcessHeap(), 0, instance->instance_id );+ HeapFree( GetProcessHeap(), 0, instance );+ return;+}++static BOOL enum_reg_usb_devices(void)+{+ SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };+ char *instance_id = NULL;+ struct DeviceInstance *instance, *instance2;+ HDEVINFO set;+ DWORD size, i = 0;+ USHORT vid, pid;+ char *str, *buf;+ BOOL ret;++ set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );+ if (set == INVALID_HANDLE_VALUE) return FALSE;++ while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))+ {+ /* get VID, PID and instance ID */+ buf = HeapAlloc( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN );+ if (buf == NULL) goto fail;+ ret = SetupDiGetDeviceInstanceIdA( set, &devInfo, buf,+ MAX_DEVICE_ID_LEN, NULL );+ if (!ret) goto fail;+ str = strstr( buf, "VID_" );+ if (str != NULL)+ {+ str += 4;+ vid = strtol( str, NULL, 16 );+ str = strstr( str, "PID_" );+ }

+ if (str == NULL)+ {+ HeapFree( GetProcessHeap(), 0, buf );+ continue;+ }+ str += 4;+ pid = strtol( str, NULL, 16 );+ str = strrchr( str, '\\' );+ if (str != NULL) ++str;+ if (str == NULL || *str == 0)+ {+ ERR( "bad instance ID\n" );+ HeapFree( GetProcessHeap(), 0, buf );+ continue;+ }+ instance_id = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );+ if (instance_id == NULL) goto fail;+ strcpy( instance_id, str );+ HeapFree( GetProcessHeap(), 0, buf );++ /* get service name */+ SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,+ NULL, NULL, 0, &size );+ buf = HeapAlloc( GetProcessHeap(), 0, size );+ if (buf == NULL) goto fail;+ ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,+ NULL, (BYTE *)buf, size, NULL );+ if (!ret)+ {+ HeapFree( GetProcessHeap(), 0, buf );+ buf = NULL;+ }++ /* add DeviceInstance structure to Devices list */+ instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );+ if (instance == NULL) goto fail;+ instance->vid = vid;+ instance->pid = pid;+ instance->instance_id = instance_id;+ instance->service = (WCHAR *)buf;+ instance->pdo = NULL;+ instance->dev = NULL;+ list_add_tail( &Devices, &instance->entry );+ instance_id = NULL;+ }++ SetupDiDestroyDeviceInfoList( set );+ return TRUE;+fail:+ HeapFree( GetProcessHeap(), 0, buf );+ HeapFree( GetProcessHeap(), 0, instance_id );+ SetupDiDestroyDeviceInfoList( set );+ LIST_FOR_EACH_ENTRY_SAFE( instance, instance2, &Devices,+ struct DeviceInstance, entry )+ {+ HeapFree( GetProcessHeap(), 0, instance->instance_id );+ HeapFree( GetProcessHeap(), 0, instance->service );+ list_remove( &instance->entry );+ HeapFree( GetProcessHeap(), 0, instance );+ }

+ return FALSE;+}++static char *new_instance_id( USHORT vid, USHORT pid )+{+ struct DeviceInstance *instance;+ char *p, *prefix = NULL;+ unsigned int id = 0, n, prefix_len = 0;+ char *ret;++ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ {+ if (vid == instance->vid && pid == instance->pid)+ {+ if (prefix == NULL)+ {+ prefix = instance->instance_id;+ p = strrchr( instance->instance_id, '&' );+ if (p == NULL) prefix_len = 0;+ else prefix_len = p + 1 - prefix;+ id = strtoul( prefix + prefix_len, NULL, 10 ) + 1;+ }+ else+ {+ p = strrchr( instance->instance_id, '&' );+ if (prefix_len)+ {+ if (p == NULL || p + 1 - instance->instance_id != prefix_len ||+ strncmp( instance->instance_id, prefix, prefix_len ))+ continue;+ }+ else if (p != NULL) continue;+ n = strtoul( instance->instance_id + prefix_len, NULL, 10 ) + 1;+ if (n > id) id = n;+ }+ }+ }+ ret = HeapAlloc( GetProcessHeap(), 0, prefix_len + 16 );+ if (ret == NULL) return NULL;+ memcpy( ret, prefix, prefix_len );+ snprintf( ret + prefix_len, prefix_len + 16, "%d", id );+ return ret;+}++static void register_usb_device( USHORT vid, USHORT pid, void *dev )+{+ static const WCHAR id_fmtW[] = {'U','S','B',+ '\\','V','i','d','_','%','0','4','x',+ '&','P','i','d','_','%','0','4','x',+ '\\','%','s',0};++ struct DeviceInstance *instance;+ HDEVINFO set = INVALID_HANDLE_VALUE;+ SP_DEVINFO_DATA devInfo;+ WCHAR *devnameW = NULL, *instance_idW = NULL;+ char *instance_id;+ ULONG size;+

+ instance_id = new_instance_id( vid, pid );+ if (instance_id == NULL) return;++ instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) );+ if (instance == NULL)+ {+ HeapFree( GetProcessHeap(), 0, instance_id );+ goto done;+ }+ instance->vid = vid;+ instance->pid = pid;+ instance->instance_id = instance_id;+ instance->service = NULL;+ instance->pdo = NULL;+ instance->dev = dev;+ list_add_tail( &Devices, &instance->entry );++ size = (strlen(instance_id) + 1) * sizeof(WCHAR);+ instance_idW = HeapAlloc( GetProcessHeap(), 0, size );+ if (instance_idW == NULL) goto done;+ RtlMultiByteToUnicodeN( instance_idW, size, NULL,+ instance_id, strlen(instance_id) + 1 );++ size = sizeof(id_fmtW) + (strlenW(instance_idW) - 2) * sizeof(WCHAR);+ devnameW = HeapAlloc( GetProcessHeap(), 0, size );+ if (devnameW == NULL) goto done;+ snprintfW( devnameW, size / sizeof(WCHAR), id_fmtW, vid, pid, instance_idW );++ set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES );+ if (set == INVALID_HANDLE_VALUE) goto done;+ devInfo.cbSize = sizeof(SP_DEVINFO_DATA);+ if (SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB,+ NULL, NULL, 0, &devInfo ))+ SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL );+done:+ if (set != INVALID_HANDLE_VALUE)+ SetupDiDestroyDeviceInfoList( set );+ HeapFree( GetProcessHeap(), 0, devnameW );+ HeapFree( GetProcessHeap(), 0, instance_idW );+}++static void start_device_drivers( DRIVER_OBJECT *hubdrv )+{+ struct DeviceInstance *instance;+ DRIVER_OBJECT *driver;+ DEVICE_OBJECT *dev;+ NTSTATUS status;++ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ {+ if (instance->service == NULL || instance->dev == NULL ||+ instance->pdo != NULL) continue;+ if (__wine_start_service( instance->service ))+ {+ instance->pdo = create_pdo( instance, hubdrv,+ DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE );+ if (instance->pdo == NULL) continue;+ while (!(driver = __wine_get_driver_object( instance->service )))+ Sleep( 100 );

+ status = __wine_add_device( driver, instance->pdo );+ dev = instance->pdo->AttachedDevice;+ if (status == STATUS_SUCCESS && dev != NULL)+ __wine_start_device( dev );+ }+ }+}++static NTSTATUS call_pnp_func( DEVICE_OBJECT *device, UCHAR minor_func )+{+ DRIVER_OBJECT *driver = device->DriverObject;+ IO_STACK_LOCATION *irpsp;+ PIRP irp;+ NTSTATUS status;++ if (driver->MajorFunction[IRP_MJ_PNP] == NULL)+ return STATUS_NOT_SUPPORTED;+ irp = IoAllocateIrp( device->StackSize, FALSE );+ if (irp == NULL) return STATUS_NO_MEMORY;++ irpsp = IoGetNextIrpStackLocation( irp );+ irp->RequestorMode = KernelMode;+ irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;+ irpsp->MajorFunction = IRP_MJ_PNP;+ irpsp->MinorFunction = minor_func;+ irpsp->DeviceObject = device;+ device->CurrentIrp = irp;+ status = IoCallDriver( device, irp );+ IoFreeIrp( irp );+ return status;+}++static void stop_device_driver( struct DeviceInstance *instance )+{+ if (instance->pdo)+ {+ NTSTATUS status;+ DEVICE_OBJECT *attd = instance->pdo->AttachedDevice;+ DEVICE_OBJECT *dev = (attd != NULL) ? attd : instance->pdo;++ status = call_pnp_func( dev, IRP_MN_SURPRISE_REMOVAL );+ if (status != STATUS_SUCCESS)+ WARN( "handling IRP_MN_SURPRISE_REMOVAL failed: %08x\n", status );+ status = call_pnp_func( dev, IRP_MN_REMOVE_DEVICE );+ if (status != STATUS_SUCCESS)+ WARN( "handling IRP_MN_REMOVE_DEVICE failed: %08x\n", status );+ IoDeleteDevice( instance->pdo );+ }+ if (instance->service)+ {+ struct DeviceInstance *it;+ BOOL stop = TRUE;++ EnterCriticalSection( &usbhub_cs );+ LIST_FOR_EACH_ENTRY( it, &Devices, struct DeviceInstance, entry )+ if (it->pdo != NULL && it->service != NULL &&+ !strcmpiW( it->service, instance->service ))+ {+ stop = FALSE;+ break;

+ }+ LeaveCriticalSection( &usbhub_cs );+ if (stop)+ stop_service( instance->service );+ }+ else+ HeapFree( GetProcessHeap(), 0, instance->instance_id );+#ifdef HAVE_LIBUSB_1+ libusb_unref_device( instance->dev );+#endif+ list_remove( &instance->entry );+ HeapFree( GetProcessHeap(), 0, instance );+}++static BOOL is_new( void *dev )+{+ struct DeviceInstance *instance;++ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ if (instance->dev == dev)+ return FALSE;+ return TRUE;+}++static int add_to_remove_list( struct DeviceInstance *it, struct list *remove )+{+ struct DeviceInstance *copy;++ if (it->service)+ {+ copy = HeapAlloc( GetProcessHeap(), 0, sizeof(*copy) );+ if (!copy) return 1;+ memcpy( copy, it, sizeof(struct DeviceInstance) );+ copy->pdo = NULL;+ copy->dev = NULL;+ list_add_tail( &Devices, &copy->entry);+ }+ list_remove( &it->entry );+ list_add_tail( remove, &it->entry );+ return 0;+}++#ifdef HAVE_LIBUSB_1++static int initialize_libusb(void)+{+ return libusb_init( NULL );+}++void add_usb_devices(void)+{+ libusb_device **devs, *dev;+ struct libusb_device_descriptor desc;+ unsigned int i = 0;+ struct DeviceInstance *instance;+ BOOL new_device;++ EnterCriticalSection( &usbhub_cs );+ if (!libusb_initialized || libusb_get_device_list( NULL, &devs ) < 0)+ goto end;

+ while ((dev = devs[i++]))+ {+ if (!is_new( dev ))+ continue;+ if (libusb_get_device_descriptor( dev, &desc ))+ {+ ERR( "failed to get USB device descriptor\n" );+ continue;+ }+ TRACE( "add %04x:%04x\n", desc.idVendor, desc.idProduct );+ libusb_ref_device( dev );+ if (libusb_get_device_address( dev ) == 1)+ {+ create_root_hub_device( desc.idVendor, desc.idProduct, dev, usbhub_driver );+ continue;+ }+ new_device = TRUE;+ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ {+ if (instance->dev == NULL && desc.idVendor == instance->vid &&+ desc.idProduct == instance->pid)+ {+ instance->dev = dev;+ new_device = FALSE;+ break;+ }+ }+ if (new_device)+ register_usb_device( desc.idVendor, desc.idProduct, dev );+ }+ libusb_free_device_list( devs, 1 );+ start_device_drivers( usbhub_driver );+end:+ LeaveCriticalSection( &usbhub_cs );+}++void remove_usb_devices(void)+{+ struct list remove_list = LIST_INIT(remove_list);+ libusb_device **devs, *dev;+ struct DeviceInstance *it, *next;+ unsigned int i;+ BOOL found;++ EnterCriticalSection( &usbhub_cs );+ if (!libusb_initialized || libusb_get_device_list( NULL, &devs ) < 0)+ goto end;+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &Devices, struct DeviceInstance, entry )+ {+ if (!it->dev)+ continue;+ found = FALSE;+ i = 0;+ while ((dev = devs[i++]))+ if (it->dev == dev)+ {+ found = TRUE;+ break;

+ }+ if (!found && add_to_remove_list( it, &remove_list ))+ break;+ }+end:+ LeaveCriticalSection( &usbhub_cs );+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &remove_list, struct DeviceInstance, entry )+ {+ TRACE( "remove %04x:%04x\n", it->vid, it->pid );+ stop_device_driver( it );+ }+}++#else /* HAVE_LIBUSB_1 */++static int initialize_libusb(void)+{+ usb_init();+ return 0;+}++void add_usb_devices(void)+{+ struct usb_device *dev;+ struct usb_bus *bus;+ struct usb_device_descriptor *desc;+ struct DeviceInstance *instance;+ BOOL new_device;++ EnterCriticalSection( &usbhub_cs );+ if (!libusb_initialized)+ goto end;+ usb_find_busses();+ usb_find_devices();+ for (bus = usb_busses; bus; bus = bus->next)+ for (dev = bus->devices; dev; dev = dev->next)+ {+ if (dev->devnum > 1 || !is_new( dev )) continue;+ desc = &dev->descriptor;+ TRACE( "add %04x:%04x\n", desc->idVendor, desc->idProduct );+ create_root_hub_device( desc->idVendor, desc->idProduct, dev,+ usbhub_driver );+ }+ for (bus = usb_busses; bus; bus = bus->next)+ for (dev = bus->devices; dev; dev = dev->next)+ {+ if (dev->devnum <= 1 || !is_new( dev )) continue;+ desc = &dev->descriptor;+ TRACE( "add %04x:%04x\n", desc->idVendor, desc->idProduct );+ new_device = TRUE;+ LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )+ {+ if (instance->dev == NULL && desc->idVendor == instance->vid &&+ desc->idProduct == instance->pid)+ {+ instance->dev = dev;+ new_device = FALSE;+ break;

+ }+ }+ if (new_device)+ register_usb_device( desc->idVendor, desc->idProduct, dev );+ }+ start_device_drivers( usbhub_driver );+end:+ LeaveCriticalSection( &usbhub_cs );+}++void remove_usb_devices(void)+{+ struct list remove_list = LIST_INIT(remove_list);+ struct usb_device *dev;+ struct usb_bus *bus;+ struct DeviceInstance *it, *next;+ BOOL found;++ EnterCriticalSection( &usbhub_cs );+ if (!libusb_initialized)+ goto end;+ usb_find_busses();+ usb_find_devices();+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &Devices, struct DeviceInstance, entry )+ {+ if (!it->dev)+ continue;+ found = FALSE;+ for (bus = usb_busses; bus; bus = bus->next)+ for (dev = bus->devices; dev; dev = dev->next)+ if (it->dev == dev)+ {+ found = TRUE;+ break;+ }+ if (!found && add_to_remove_list( it, &remove_list ))+ break;+ }+end:+ LeaveCriticalSection( &usbhub_cs );+ LIST_FOR_EACH_ENTRY_SAFE( it, next, &remove_list, struct DeviceInstance, entry )+ {+ TRACE( "remove %04x:%04x\n", it->vid, it->pid );+ stop_device_driver( it );+ }+}++#endif /* HAVE_LIBUSB_1 */++#else /* defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1) */++void add_usb_devices(void)+{+}++void remove_usb_devices(void)+{+}

++#endif /* defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1) */++#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)++#ifdef HAVE_LIBUDEV++static void *start_udev(void)+{+ struct udev *udev;+ struct udev_monitor *mon;+ int ret;++ udev = udev_new();+ if (!udev)+ return NULL;++ mon = udev_monitor_new_from_netlink( udev, "udev" );+ if (!mon) goto end;+ ret = udev_monitor_filter_add_match_subsystem_devtype( mon, "usb", "usb_device" );+ if (ret < 0) goto end;+ ret = udev_monitor_enable_receiving( mon );+ if (ret < 0) goto end;+ return mon;+end:+ udev_monitor_unref( mon );+ udev_unref( udev );+ return NULL;+}++static void loop_udev( void *mon )+{+ struct pollfd fds;+ int ret, fd = udev_monitor_get_fd( mon );++ fds.fd = fd;+ fds.events = POLLIN;++ for(;;)+ {+ fds.revents = 0;+ ret = poll( &fds, 1, -1 );+ if (ret == 1 && (fds.revents & POLLIN))+ {+ struct udev_device *dev = udev_monitor_receive_device( mon );++ if (dev)+ {+ const char *action = udev_device_get_action( dev );++ if (action)+ {+ if (!strcmp( action, "add" ))+ add_usb_devices();+ else if (!strcmp( action, "remove" ))+ remove_usb_devices();+ }+ udev_device_unref( dev );+ }

+ }+ }+}++#else /* HAVE_LIBUDEV */++static void *start_udev(void)+{+ return NULL;+}++static void loop_udev( void *mon )+{+}++#endif /* HAVE_LIBUDEV */++static DWORD CALLBACK initialize_usbhub( void *arg )+{+ static const WCHAR usbhub_started_eventW[] = {'_','_','w','i','n','e',+ '_','U','s','b','h','u','b',+ 'S','t','a','r','t','e','d',0};++ HANDLE event;+ void *monitor;++ EnterCriticalSection( &usbhub_cs );+ if (!enum_reg_usb_devices())+ ERR( "failed to enumerate USB devices\n" );+ else if (initialize_libusb())+ ERR( "failed to initialize libusb\n" );+ else+ libusb_initialized = TRUE;+ LeaveCriticalSection( &usbhub_cs );+ monitor = start_udev();+ add_usb_devices();+ event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );+ SetEvent( event );+ CloseHandle( event );+ if (monitor)+ loop_udev( monitor );+ return 0;+}++#endif /* defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1) */++NTSTATUS WINAPI usbhub_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path )+{+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)+ HANDLE thread;++ usbhub_driver = driver;+ driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = usbhub_ioctl;+ driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl;+ driver->MajorFunction[IRP_MJ_PNP] = usbhub_dispatch_pnp;++ thread = CreateThread( NULL, 0, initialize_usbhub, NULL, 0, NULL );

+ if (!thread) return STATUS_UNSUCCESSFUL;+ CloseHandle( thread );+#else+ TRACE( "USB support not compiled in\n" );+#endif+ return STATUS_SUCCESS;+}diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.inindex 2ab6d49..792d875 100644--- a/dlls/ntoskrnl.exe/Makefile.in+++ b/dlls/ntoskrnl.exe/Makefile.in@@ -1,5 +1,6 @@ MODULE = ntoskrnl.exe IMPORTLIB = ntoskrnl.exe+IMPORTS = setupapi advapi32 C_SRCS = \ instr.c \diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.cindex 285541a..b852275 100644--- a/dlls/ntoskrnl.exe/ntoskrnl.c+++ b/dlls/ntoskrnl.exe/ntoskrnl.c@@ -26,14 +26,22 @@ #define NONAMELESSUNION #define NONAMELESSSTRUCT+#define INITGUID #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winternl.h"+#include "winbase.h"+#include "winsvc.h"+#include "winuser.h"+#include "winreg.h"+#include "setupapi.h"+#include "cfgmgr32.h" #include "excpt.h" #include "winioctl.h" #include "ddk/ntddk.h"+#include "ddk/wdmguid.h" #include "wine/unicode.h" #include "wine/server.h" #include "wine/list.h"@@ -61,6 +69,15 @@ KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4] = { { 0 } }; typedef void (WINAPI *PCREATE_PROCESS_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN); typedef void (WINAPI *PCREATE_THREAD_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN); +static CRITICAL_SECTION cs;+static CRITICAL_SECTION_DEBUG cs_debug =+{+ 0, 0, &cs,+ { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },+ 0, 0, { (DWORD_PTR)(__FILE__ ": cs") }+};+static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };+ static struct list Irps = LIST_INIT(Irps);

struct IrpInstance@@ -69,12 +86,65 @@ struct IrpInstance IRP *irp; }; -/* tid of the thread running client request */-static DWORD request_thread;+static struct list DriverObjExtensions = LIST_INIT(DriverObjExtensions);++struct DriverObjExtension+{+ struct list entry;+ void *ptr;+ DRIVER_OBJECT *driver;+ void *id_addr;+};++static struct list Drivers = LIST_INIT(Drivers);++struct DriverInstance+{+ struct list entry;+ DRIVER_OBJECT *driver;+ const WCHAR *service;+ DWORD driver_thread_id;+ DWORD client_tid;+ DWORD client_pid;+};++static struct list Interfaces = LIST_INIT(Interfaces);++struct InterfaceInstance+{+ struct list entry;+ WCHAR *link;+ UNICODE_STRING target;+ GUID guid;+ int active;+};++static struct list InterfaceChangeNotifications = LIST_INIT(InterfaceChangeNotifications);++struct InterfaceChangeNotification+{+ struct list entry;+ GUID interface_class;+ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE callback;+ void *context;+};++struct callback+{+ struct list entry;+ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE routine;+ void *context;+};++static struct list Handles = LIST_INIT(Handles);

-/* pid/tid of the client thread */-static DWORD client_tid;-static DWORD client_pid;+struct HandleInstance+{+ struct list entry;+ void *object;+ HANDLE handle;+ ULONG refs;+}; #ifdef __i386__ #define DEFINE_FASTCALL1_ENTRYPOINT( name ) \@@ -105,6 +175,192 @@ static inline LPCSTR debugstr_us( const UNICODE_STRING *us ) return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) ); } +BOOL CDECL __wine_start_service( const WCHAR *name )+{+ SC_HANDLE scm, service;+ BOOL ret;++ scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );+ if (scm == NULL)+ return FALSE;++ service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );+ if (service == NULL)+ {+ CloseServiceHandle( scm );+ return FALSE;+ }++ do {+ ret = StartServiceW( service, 0, NULL );+ if (!ret)+ {+ if (ERROR_SERVICE_ALREADY_RUNNING == GetLastError())+ ret = TRUE;+ else if (ERROR_SERVICE_DATABASE_LOCKED == GetLastError())+ Sleep( 100 );+ else+ break;+ }+ } while (!ret);++ CloseServiceHandle( service );+ CloseServiceHandle( scm );++ return ret;+}++/* get name of driver service for device with given id */+static BOOL get_service( WCHAR *device_id, WCHAR **service_name )+{+ SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };+ HDEVINFO set;+ WCHAR *ptr, *enum_name, *id = NULL;

+ DWORD size, i = 0;+ BOOL ret;++ *service_name = NULL;+ ptr = strchrW( device_id, '\\' );+ if (!ptr) return FALSE;+ size = ptr - device_id + 1;+ enum_name = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );+ if (!enum_name) return FALSE;+ lstrcpynW( enum_name, device_id, size );++ set = SetupDiGetClassDevsW( NULL, enum_name, 0, DIGCF_ALLCLASSES );+ if (set == INVALID_HANDLE_VALUE) goto end;+ while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))+ {+ SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,+ NULL, NULL, 0, &size );+ if (id) RtlFreeHeap( GetProcessHeap(), 0, id );+ id = RtlAllocateHeap( GetProcessHeap(), 0, size );+ if (!id) break;+ ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,+ NULL, (BYTE *)id, size, NULL );+ if (!ret) break;+ if (strcmpiW( device_id, id )) continue;+ SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,+ NULL, NULL, 0, &size );+ *service_name = RtlAllocateHeap( GetProcessHeap(), 0, size );+ if (!*service_name) break;+ ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,+ NULL, (BYTE *)*service_name, size, NULL );+ if (!ret)+ {+ RtlFreeHeap( GetProcessHeap(), 0, *service_name );+ *service_name = NULL;+ break;+ }+ }+ SetupDiDestroyDeviceInfoList( set );+end:+ if (id) RtlFreeHeap( GetProcessHeap(), 0, id );+ if (enum_name) RtlFreeHeap( GetProcessHeap(), 0, enum_name );+ return (*service_name != NULL);+}++static NTSTATUS get_device_id( DEVICE_OBJECT *pdo, BUS_QUERY_ID_TYPE id_type,+ WCHAR **id )+{+ NTSTATUS status;+ IO_STACK_LOCATION *irpsp;+ IRP *irp;++ *id = NULL;+ irp = IoAllocateIrp( pdo->StackSize, FALSE );+ if (irp == NULL) return STATUS_NO_MEMORY;+ irpsp = IoGetNextIrpStackLocation( irp );+ irpsp->MajorFunction = IRP_MJ_PNP;+ irpsp->MinorFunction = IRP_MN_QUERY_ID;+ irpsp->Parameters.QueryId.IdType = id_type;+ status = IoCallDriver( pdo, irp );

+ if (status == STATUS_SUCCESS)+ *id = (WCHAR *)irp->IoStatus.Information;+ IoFreeIrp( irp );+ return status;+}++static BOOL compare_ids( WCHAR *hardware_id, WCHAR *instance_id,+ WCHAR *device_instance_id )+{+ WCHAR *ptr, *ptr2;++ ptr = strrchrW( device_instance_id, '\\' );+ if (ptr == NULL) return FALSE;+ if (strncmpiW( hardware_id, device_instance_id, ptr - device_instance_id ))+ return FALSE;+ ++ptr;+ ptr2 = strrchrW( ptr, '&' );+ ptr2 = ptr2 ? (ptr2 + 1) : ptr;+ if (strcmpiW( instance_id, ptr2 ))+ return FALSE;+ return TRUE;+}++/* caller is responsible for proper locking to prevent modifying Interfaces list */+static struct InterfaceInstance *get_registered_interface( WCHAR *name, USHORT len )+{+ struct InterfaceInstance *interf;++ LIST_FOR_EACH_ENTRY( interf, &Interfaces, struct InterfaceInstance, entry )+ {+ if (!strncmpW( name, interf->link, len ))+ return interf;+ }+ return NULL;+}++static void call_interface_change_callbacks( const GUID *interface_class,+ UNICODE_STRING *link_name )+{+ struct list callbacks = LIST_INIT(callbacks);+ struct InterfaceChangeNotification *notification;+ struct callback *cb, *cb2;+ DEVICE_INTERFACE_CHANGE_NOTIFICATION change_notification;+ NTSTATUS callback_status;++ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( notification, &InterfaceChangeNotifications,+ struct InterfaceChangeNotification, entry )+ {+ if (!memcmp( interface_class, &notification->interface_class,+ sizeof(*interface_class) ))+ {+ cb = HeapAlloc( GetProcessHeap(), 0, sizeof(*cb) );+ if (cb == NULL) break;+ cb->routine = notification->callback;+ cb->context = notification->context;+ list_add_tail( &callbacks, &cb->entry );+ }

+ }+ LeaveCriticalSection( &cs );++ change_notification.Version = 1;+ change_notification.Size = sizeof(change_notification);+ change_notification.Event = GUID_DEVICE_INTERFACE_ARRIVAL;+ change_notification.InterfaceClassGuid = *interface_class;+ change_notification.SymbolicLinkName = link_name;++ LIST_FOR_EACH_ENTRY_SAFE( cb, cb2, &callbacks, struct callback, entry )+ {+ if (TRACE_ON(relay))+ DPRINTF( "%04x:Call callback %p (notification=%p,context=%p)\n",+ GetCurrentThreadId(), cb->routine, &change_notification,+ cb->context );++ callback_status = cb->routine( &change_notification, cb->context );++ if (TRACE_ON(relay))+ DPRINTF( "%04x:Ret callback %p (notification=%p,context=%p) retval=%08x\n",+ GetCurrentThreadId(), cb->routine, &change_notification,+ cb->context, callback_status );++ list_remove( &cb->entry );+ HeapFree( GetProcessHeap(), 0, cb );+ }+}+ static HANDLE get_device_manager(void) { static HANDLE device_manager;@@ -133,74 +389,134 @@ static HANDLE get_device_manager(void) return ret; } -/* process an ioctl request for a given device */-static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size,- void *out_buff, ULONG *out_size )+static NTSTATUS get_autogenerated_device_name( UNICODE_STRING *name ) {- IRP irp;- MDL mdl;- IO_STACK_LOCATION irpsp;- PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];+ static const WCHAR autogen_nameW[] = {'\\','D','e','v','i','c','e',+ '\\','%','0','8','x',0};+ NTSTATUS status;- LARGE_INTEGER count;+ WCHAR *nameW;+ HANDLE handle;+ OBJECT_ATTRIBUTES attr;+ IO_STATUS_BLOCK io;+ unsigned int k = 1;

- TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size );+ if (!(nameW = RtlAllocateHeap( GetProcessHeap(), 0, 17 * sizeof(WCHAR) )))+ return STATUS_NO_MEMORY; - /* so we can spot things that we should initialize */- memset( &irp, 0x55, sizeof(irp) );- memset( &irpsp, 0x66, sizeof(irpsp) );- memset( &mdl, 0x77, sizeof(mdl) );+ attr.Length = sizeof(attr);+ attr.RootDirectory = 0;+ attr.Attributes = OBJ_CASE_INSENSITIVE;+ attr.ObjectName = name;+ attr.SecurityDescriptor = NULL;+ attr.SecurityQualityOfService = NULL; - irp.RequestorMode = UserMode;- if ((code & 3) == METHOD_BUFFERED)+ for (;;) {- irp.AssociatedIrp.SystemBuffer = HeapAlloc( GetProcessHeap(), 0, max( in_size, *out_size ) );- if (!irp.AssociatedIrp.SystemBuffer)- return STATUS_NO_MEMORY;- memcpy( irp.AssociatedIrp.SystemBuffer, in_buff, in_size );+ sprintfW( nameW, autogen_nameW, k );+ RtlInitUnicodeString( name, nameW );+ status = NtCreateFile( &handle, 0, &attr, &io, NULL, 0, 0,+ FILE_OPEN, 0, NULL, 0 );+ if (status != STATUS_SUCCESS) break;+ NtClose( handle );+ ++k; }- else- irp.AssociatedIrp.SystemBuffer = in_buff;- irp.UserBuffer = out_buff;- irp.MdlAddress = &mdl;- irp.Tail.Overlay.s.u2.CurrentStackLocation = &irpsp;- irp.UserIosb = NULL;-- irpsp.MajorFunction = IRP_MJ_DEVICE_CONTROL;- irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;- irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;- irpsp.Parameters.DeviceIoControl.IoControlCode = code;- irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff;- irpsp.DeviceObject = device;- irpsp.CompletionRoutine = NULL;-- mdl.Next = NULL;- mdl.Size = 0;- mdl.StartVa = out_buff;- mdl.ByteCount = *out_size;- mdl.ByteOffset = 0;-- device->CurrentIrp = &irp;+ return STATUS_SUCCESS;+} - KeQueryTickCount( &count ); /* update the global KeTickCount */+/* get id of the thread whose request is being handled */

+static DWORD get_client_tid(void)+{+ DWORD ret = 0, thread_id = GetCurrentThreadId();+ struct DriverInstance *drv; - if (TRACE_ON(relay))- DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n",- GetCurrentThreadId(), dispatch, device, &irp );+ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry )+ {+ if (drv->driver_thread_id == thread_id)+ {+ ret = drv->client_tid;+ break;+ }+ }+ LeaveCriticalSection( &cs );+ return ret;+} - status = dispatch( device, &irp );+/* get id of the process whose request is being handled */+static DWORD get_client_pid(void)+{+ DWORD ret = 0, thread_id = GetCurrentThreadId();+ struct DriverInstance *drv; - if (TRACE_ON(relay))- DPRINTF( "%04x:Ret driver dispatch %p (device=%p,irp=%p) retval=%08x\n",- GetCurrentThreadId(), dispatch, device, &irp, status );+ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry )+ {+ if (drv->driver_thread_id == thread_id)+ {+ ret = drv->client_pid;+ break;+ }+ }+ LeaveCriticalSection( &cs );+ return ret;+} - *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0;- if ((code & 3) == METHOD_BUFFERED)+/* save ids of the thread whose request is being handled */+static void save_client_ids( DWORD tid, DWORD pid )+{+ DWORD thread_id = GetCurrentThreadId();+ struct DriverInstance *drv;++ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry ) {- memcpy( out_buff, irp.AssociatedIrp.SystemBuffer, *out_size );- HeapFree( GetProcessHeap(), 0, irp.AssociatedIrp.SystemBuffer );+ if (drv->driver_thread_id == thread_id)+ {

+ drv->client_tid = tid;+ drv->client_pid = pid;+ break;+ } }- return irp.IoStatus.u.Status;+ LeaveCriticalSection( &cs );+}++/* process an ioctl request for a given device */+static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size,+ void *out_buff, ULONG *out_size )+{+ PIRP irp;+ PIO_STACK_LOCATION irpsp;+ PFILE_OBJECT file;+ NTSTATUS status;+ LARGE_INTEGER count;+ IO_STATUS_BLOCK iosb;++ TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size );++ file = ExAllocatePool( NonPagedPool, sizeof(*file) );+ if (file == NULL)+ return STATUS_NO_MEMORY;+ irp = IoBuildDeviceIoControlRequest( code, device, in_buff, in_size,+ out_buff, *out_size, FALSE, NULL, &iosb );+ if (irp == NULL)+ {+ ExFreePool( file );+ return STATUS_NO_MEMORY;+ }+ irpsp = IoGetNextIrpStackLocation( irp );+ irp->RequestorMode = UserMode;+ irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;+ irp->Tail.Overlay.OriginalFileObject = file;+ device->CurrentIrp = irp;+ file->Type = IO_TYPE_FILE;+ file->Size = sizeof(*file);+ file->DeviceObject = device;++ KeQueryTickCount( &count ); /* update the global KeTickCount */+ status = IoCallDriver( device, irp );+ *out_size = (status >= 0) ? iosb.Information : 0;+ return status; } @@ -217,8 +533,8 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) DEVICE_OBJECT *device = NULL; ULONG in_size = 4096, out_size = 0; HANDLE handles[2];-- request_thread = GetCurrentThreadId();+ DWORD client_tid = 0;+ DWORD client_pid = 0; if (!(in_buff = HeapAlloc( GetProcessHeap(), 0, in_size )))

{@@ -257,12 +573,16 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) } SERVER_END_REQ; + save_client_ids( client_tid, client_pid );+ switch(status) { case STATUS_SUCCESS: HeapFree( GetProcessHeap(), 0, out_buff ); if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ); else out_buff = NULL;+ while (device->AttachedDevice)+ device = device->AttachedDevice; status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size ); break; case STATUS_BUFFER_OVERFLOW:@@ -284,6 +604,165 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) /***********************************************************************+ * __wine_add_driver_object (Not a Windows API)+ */+BOOL CDECL __wine_add_driver_object( DRIVER_OBJECT *driver, const WCHAR *service )+{+ struct DriverInstance *drv;++ drv = HeapAlloc( GetProcessHeap(), 0, sizeof(*drv) );+ if (drv == NULL) return FALSE;+ drv->driver = driver;+ drv->service = service;+ drv->driver_thread_id = GetCurrentThreadId();+ drv->client_tid = 0;+ drv->client_pid = 0;+ EnterCriticalSection( &cs );+ list_add_tail( &Drivers, &drv->entry );+ LeaveCriticalSection( &cs );+ return TRUE;+}+++/***********************************************************************+ * __wine_del_driver_object (Not a Windows API)+ */+void CDECL __wine_del_driver_object( const DRIVER_OBJECT *driver )+{+ struct DriverInstance *drv;++ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry )+ {+ if (drv->driver == driver)+ {+ list_remove( &drv->entry );

+ HeapFree( GetProcessHeap(), 0, drv );+ break;+ }+ }+ LeaveCriticalSection( &cs );+}+++/***********************************************************************+ * __wine_get_driver_object (Not a Windows API)+ */+DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service )+{+ struct DriverInstance *drv;+ DRIVER_OBJECT *driver_obj = NULL;++ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry )+ {+ if (!strcmpiW( drv->service, service ))+ {+ driver_obj = drv->driver;+ break;+ }+ }+ LeaveCriticalSection( &cs );+ return driver_obj;+}+++/***********************************************************************+ * __wine_add_device (Not a Windows API)+ */+NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev )+{+ NTSTATUS status;+ NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) =+ driver->DriverExtension->AddDevice;++ if (TRACE_ON(relay))+ DPRINTF( "%04x:Call AddDevice %p (%p,%p)\n",+ GetCurrentThreadId(), AddDevice, driver, dev );++ status = AddDevice( driver, dev );++ if (TRACE_ON(relay))+ DPRINTF( "%04x:Ret AddDevice %p (%p,%p) retval=%08x\n",+ GetCurrentThreadId(), AddDevice, driver, dev, status );++ return status;+}+++/***********************************************************************+ * __wine_start_device (Not a Windows API)+ */+NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device )+{+ DRIVER_OBJECT *driver = device->DriverObject;+ IO_STACK_LOCATION *irpsp;

+ PIRP irp;+ NTSTATUS status;++ if (driver->MajorFunction[IRP_MJ_PNP] == NULL)+ return STATUS_NOT_SUPPORTED;+ irp = IoAllocateIrp( device->StackSize, FALSE );+ if (irp == NULL) return STATUS_NO_MEMORY;++ irpsp = IoGetNextIrpStackLocation( irp );+ irp->RequestorMode = KernelMode;+ irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;+ irpsp->MajorFunction = IRP_MJ_PNP;+ irpsp->MinorFunction = IRP_MN_START_DEVICE;+ irpsp->DeviceObject = device;+ device->CurrentIrp = irp;+ status = IoCallDriver( device, irp );+ IoFreeIrp( irp );+ return status;+}+++/***********************************************************************+ * ExAcquireFastMutexUnsafe (NTOSKRNL.EXE.@)+ */+#ifdef DEFINE_FASTCALL1_ENTRYPOINT+DEFINE_FASTCALL1_ENTRYPOINT( ExAcquireFastMutexUnsafe )+void WINAPI __regs_ExAcquireFastMutexUnsafe( PFAST_MUTEX FastMutex )+#else+void WINAPI ExAcquireFastMutexUnsafe( PFAST_MUTEX FastMutex )+#endif+{+ FIXME( "stub: %p\n", FastMutex );+}+++/***********************************************************************+ * ExReleaseFastMutexUnsafe (NTOSKRNL.EXE.@)+ */+#ifdef DEFINE_FASTCALL1_ENTRYPOINT+DEFINE_FASTCALL1_ENTRYPOINT( ExReleaseFastMutexUnsafe )+void WINAPI __regs_ExReleaseFastMutexUnsafe( PFAST_MUTEX FastMutex )+#else+void WINAPI ExReleaseFastMutexUnsafe( PFAST_MUTEX FastMutex )+#endif+{+ FIXME( "stub: %p\n", FastMutex );+}+++/***********************************************************************+ * IoAcquireCancelSpinLock (NTOSKRNL.EXE.@)+ */+void WINAPI IoAcquireCancelSpinLock( PKIRQL Irql )+{+ FIXME( "stub: %p\n", Irql );+}++/***********************************************************************+ * IoReleaseCancelSpinLock (NTOSKRNL.EXE.@)+ */

+void WINAPI IoReleaseCancelSpinLock( KIRQL Irql )+{+ FIXME( "stub: %u\n", Irql );+}++/*********************************************************************** * IoAllocateDriverObjectExtension (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject,@@ -291,11 +770,31 @@ NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject, ULONG DriverObjectExtensionSize, PVOID *DriverObjectExtension ) {- FIXME( "stub: %p, %p, %u, %p\n", DriverObject, ClientIdentificationAddress,+ struct DriverObjExtension *ext;++ TRACE( "%p, %p, %u, %p\n", DriverObject, ClientIdentificationAddress, DriverObjectExtensionSize, DriverObjectExtension );- return STATUS_NOT_IMPLEMENTED;-} + *DriverObjectExtension = NULL;+ if (IoGetDriverObjectExtension( DriverObject, ClientIdentificationAddress ))+ return STATUS_OBJECT_NAME_COLLISION;+ ext = ExAllocatePool( NonPagedPool, sizeof(*ext) );+ if (ext == NULL)+ return STATUS_INSUFFICIENT_RESOURCES;+ ext->ptr = ExAllocatePool( NonPagedPool, DriverObjectExtensionSize );+ if (ext->ptr == NULL)+ {+ ExFreePool( ext );+ return STATUS_INSUFFICIENT_RESOURCES;+ }+ ext->driver = DriverObject;+ ext->id_addr = ClientIdentificationAddress;+ EnterCriticalSection( &cs );+ list_add_tail( &DriverObjExtensions, &ext->entry );+ LeaveCriticalSection( &cs );+ *DriverObjectExtension = ext->ptr;+ return STATUS_SUCCESS;+} /*********************************************************************** * IoGetDriverObjectExtension (NTOSKRNL.EXE.@)@@ -303,10 +802,24 @@ NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject, PVOID WINAPI IoGetDriverObjectExtension( PDRIVER_OBJECT DriverObject, PVOID ClientIdentificationAddress ) {- FIXME( "stub: %p, %p\n", DriverObject, ClientIdentificationAddress );- return NULL;-}+ struct DriverObjExtension *ext;+ void *ext_ptr = NULL;++ TRACE( "%p, %p\n", DriverObject, ClientIdentificationAddress );

+ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( ext, &DriverObjExtensions, struct DriverObjExtension, entry )+ {+ if (DriverObject == ext->driver &&+ ClientIdentificationAddress == ext->id_addr)+ {+ ext_ptr = ext->ptr;+ break;+ }+ }+ LeaveCriticalSection( &cs );+ return ext_ptr;+} /*********************************************************************** * IoInitializeIrp (NTOSKRNL.EXE.@)@@ -396,12 +909,73 @@ PVOID WINAPI IoAllocateErrorLogEntry( PVOID IoObject, UCHAR EntrySize ) */ PMDL WINAPI IoAllocateMdl( PVOID VirtualAddress, ULONG Length, BOOLEAN SecondaryBuffer, BOOLEAN ChargeQuota, PIRP Irp ) {- FIXME( "stub: %p, %u, %i, %i, %p\n", VirtualAddress, Length, SecondaryBuffer, ChargeQuota, Irp );+ HANDLE process;+ PMDL mdl;+ PVOID ptr;+ SIZE_T bytes_read;+ DWORD process_id = get_client_pid();++ TRACE( "%p, %u, %i, %i, %p\n", VirtualAddress, Length, SecondaryBuffer,+ ChargeQuota, Irp );++ mdl = ExAllocatePool( NonPagedPool, sizeof(*mdl) );+ if (NULL == mdl)+ return NULL;++ RtlZeroMemory( mdl, sizeof(*mdl) );+ mdl->ByteCount = Length;+ mdl->StartVa = VirtualAddress;++ if (process_id)+ {+ ptr = ExAllocatePool( NonPagedPool, Length );+ if (NULL == ptr)+ goto fail;+ process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, process_id );+ if (NULL == process)+ goto fail;+ NtReadVirtualMemory( process, VirtualAddress, ptr, Length, &bytes_read );+ CloseHandle( process );+ mdl->MappedSystemVa = ptr;+ }+ else+ mdl->MappedSystemVa = VirtualAddress;++ return mdl;+fail:

+ if (ptr) ExFreePool( ptr );+ if (mdl) ExFreePool( mdl ); return NULL; } /***********************************************************************+ * IoFreeMdl (NTOSKRNL.EXE.@)+ */+void WINAPI IoFreeMdl( MDL *mdl )+{+ HANDLE process;+ SIZE_T bytes_written;+ DWORD process_id = get_client_pid();++ TRACE( "%p\n", mdl );++ if (process_id)+ {+ process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, process_id );+ if (NULL != process)+ {+ NtWriteVirtualMemory( process, mdl->StartVa, mdl->MappedSystemVa,+ mdl->ByteCount, &bytes_written );+ CloseHandle( process );+ }+ ExFreePool( mdl->MappedSystemVa );+ }+ ExFreePool( mdl );+}+++/*********************************************************************** * IoAllocateWorkItem (NTOSKRNL.EXE.@) */ PIO_WORKITEM WINAPI IoAllocateWorkItem( PDEVICE_OBJECT DeviceObject )@@ -418,6 +992,8 @@ PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source, DEVICE_OBJECT *target ) { TRACE( "%p, %p\n", source, target );+ while (target->AttachedDevice)+ target = target->AttachedDevice; target->AttachedDevice = source; source->StackSize = target->StackSize + 1; return target;@@ -425,6 +1001,16 @@ PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source, /***********************************************************************+ * IoDetachDevice (NTOSKRNL.EXE.@)+ */+void WINAPI IoDetachDevice( DEVICE_OBJECT *device )+{+ TRACE( "%p\n", device );+ device->AttachedDevice = NULL;+}++

+/*********************************************************************** * IoBuildDeviceIoControlRequest (NTOSKRNL.EXE.@) */ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode,@@ -440,6 +1026,8 @@ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode, PIRP irp; PIO_STACK_LOCATION irpsp; struct IrpInstance *instance;+ CHAR *buf = NULL;+ MDL *mdl = NULL; TRACE( "%x, %p, %p, %u, %p, %u, %u, %p, %p\n", IoControlCode, DeviceObject, InputBuffer, InputBufferLength,@@ -453,23 +1041,59 @@ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode, if (irp == NULL) return NULL; - instance = HeapAlloc( GetProcessHeap(), 0, sizeof(struct IrpInstance) );- if (instance == NULL)- {- IoFreeIrp( irp );- return NULL;- }- instance->irp = irp;- list_add_tail( &Irps, &instance->entry );- irpsp = IoGetNextIrpStackLocation( irp ); irpsp->MajorFunction = InternalDeviceIoControl ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; irpsp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;+ irpsp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;+ irpsp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; irp->UserIosb = IoStatusBlock; irp->UserEvent = Event; + switch (IoControlCode & 3)+ {+ case METHOD_BUFFERED:+ buf = ExAllocatePool( NonPagedPool, max( OutputBufferLength, InputBufferLength ) );+ if (buf == NULL)+ goto err;+ memcpy( buf, InputBuffer, InputBufferLength );+ irp->AssociatedIrp.SystemBuffer = buf;+ irp->UserBuffer = OutputBuffer;+ break;+ case METHOD_NEITHER:+ irpsp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;+ irp->UserBuffer = OutputBuffer;+ break;+ default:+ irp->AssociatedIrp.SystemBuffer = InputBuffer;+ mdl = ExAllocatePool( NonPagedPool, sizeof(*mdl) );+ if (mdl == NULL)+ goto err;+ mdl->Next = NULL;+ mdl->Size = 0;+ mdl->StartVa = OutputBuffer;

+ mdl->MappedSystemVa = OutputBuffer;+ mdl->ByteCount = OutputBufferLength;+ mdl->ByteOffset = 0;+ irp->MdlAddress = mdl;+ }++ instance = HeapAlloc( GetProcessHeap(), 0, sizeof(struct IrpInstance) );+ if (instance == NULL)+ goto err;+ instance->irp = irp;+ EnterCriticalSection( &cs );+ list_add_tail( &Irps, &instance->entry );+ LeaveCriticalSection( &cs );+ return irp;+err:+ if (buf)+ ExFreePool( buf );+ if (mdl)+ ExFreePool( mdl );+ IoFreeIrp( irp );+ return NULL; } @@ -532,6 +1156,7 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, DEVICE_OBJECT *device; HANDLE handle = 0; HANDLE manager = get_device_manager();+ UNICODE_STRING generated_name; TRACE( "(%p, %u, %s, %u, %x, %u, %p)\n", driver, ext_size, debugstr_us(name), type, characteristics, exclusive, ret_device );@@ -539,6 +1164,17 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, if (!(device = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*device) + ext_size ))) return STATUS_NO_MEMORY; + if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME)+ {+ status = get_autogenerated_device_name( &generated_name );+ if (status != STATUS_SUCCESS)+ {+ HeapFree( GetProcessHeap(), 0, device );+ return status;+ }+ name = &generated_name;+ }+ SERVER_START_REQ( create_device ) { req->access = 0;@@ -553,7 +1189,11 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, if (status == STATUS_SUCCESS) {

+ device->Type = IO_TYPE_DEVICE;+ device->Size = sizeof(*device) + ext_size; device->DriverObject = driver;+ device->Flags = DO_DEVICE_INITIALIZING;+ if (name) device->Flags |= DO_DEVICE_HAS_NAME; device->DeviceExtension = device + 1; device->DeviceType = type; device->StackSize = 1;@@ -566,6 +1206,8 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, } else HeapFree( GetProcessHeap(), 0, device ); + if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME)+ RtlFreeUnicodeString( &generated_name ); return status; } @@ -619,6 +1261,188 @@ NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *targ /***********************************************************************+ * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@)+ */+void WINAPI IoInvalidateDeviceRelations( PDEVICE_OBJECT DeviceObject,+ DEVICE_RELATION_TYPE Type )+{+ TRACE( "%p, %u\n", DeviceObject, Type );++ while (DeviceObject->AttachedDevice)+ DeviceObject = DeviceObject->AttachedDevice;+ if (Type == BusRelations)+ {+ DEVICE_RELATIONS *rel;+ IO_STACK_LOCATION *irpsp;+ IRP *irp;+ NTSTATUS status;++ irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );+ if (irp == NULL) return;+ irpsp = IoGetNextIrpStackLocation( irp );+ irpsp->MajorFunction = IRP_MJ_PNP;+ irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;+ irpsp->Parameters.QueryDeviceRelations.Type = BusRelations;+ status = IoCallDriver( DeviceObject, irp );+ rel = (DEVICE_RELATIONS *)irp->IoStatus.Information;+ if (status == STATUS_SUCCESS && rel && rel->Count)+ {+ unsigned int k;++ for (k = 0; k < rel->Count; ++k)+ {+ IoFreeIrp( irp );+ irp = IoAllocateIrp( rel->Objects[k]->StackSize, FALSE );+ if (irp == NULL) return;+ irpsp = IoGetNextIrpStackLocation( irp );+ irpsp->MajorFunction = IRP_MJ_PNP;+ irpsp->MinorFunction = IRP_MN_QUERY_ID;+ irpsp->Parameters.QueryId.IdType = BusQueryDeviceID;

+ status = IoCallDriver( rel->Objects[k], irp );+ if (status == STATUS_SUCCESS)+ {+ WCHAR *service;++ if (get_service( (WCHAR *)irp->IoStatus.Information, &service )+ && __wine_start_service( service ))+ {+ DRIVER_OBJECT *driver;++ while (!(driver = __wine_get_driver_object( service )))+ Sleep( 100 );+ status = __wine_add_device( driver, rel->Objects[k] );+ if (status == STATUS_SUCCESS &&+ rel->Objects[k]->AttachedDevice)+ __wine_start_device( rel->Objects[k]->AttachedDevice );+ }+ if (service) RtlFreeHeap( GetProcessHeap(), 0, service );+ }+ ExFreePool( (void *)irp->IoStatus.Information );+ }+ ExFreePool( rel );+ }+ IoFreeIrp( irp );+ }+ else+ FIXME( "DEVICE_RELATION_TYPE %u not implemented\n", Type );+}+++/***********************************************************************+ * IoRegisterDeviceInterface (NTOSKRNL.EXE.@)+ */+NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT PhysicalDeviceObject,+ CONST GUID *InterfaceClassGuid,+ PUNICODE_STRING ReferenceString,+ PUNICODE_STRING SymbolicLinkName )+{+ WCHAR *hardware_id = NULL, *instance_id = NULL, *id = NULL;+ WCHAR *ptr, *target, *enumerator = NULL;+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = NULL;+ HDEVINFO set;+ SP_DEVINFO_DATA devInfo;+ SP_DEVICE_INTERFACE_DATA interfaceData;+ DWORD i = 0;+ NTSTATUS status;+ struct InterfaceInstance *interf;+ DWORD size;++ TRACE( "%p %s %s %p\n", PhysicalDeviceObject,+ debugstr_guid(InterfaceClassGuid), debugstr_us(ReferenceString),+ SymbolicLinkName );++ status = get_device_id( PhysicalDeviceObject, BusQueryInstanceID, &instance_id );+ if (status != STATUS_SUCCESS) goto end;+ status = get_device_id( PhysicalDeviceObject, BusQueryDeviceID, &hardware_id );

+ if (status != STATUS_SUCCESS) goto end;+ ptr = strchrW( hardware_id, '\\' ) + 1;+ size = (char *)ptr - (char *)hardware_id;+ enumerator = RtlAllocateHeap( GetProcessHeap(), 0, size );+ id = RtlAllocateHeap( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN );+ if (enumerator == NULL || id == NULL)+ {+ status = STATUS_NO_MEMORY;+ goto end;+ }+ lstrcpynW( enumerator, hardware_id, size / sizeof(WCHAR) );++ status = STATUS_UNSUCCESSFUL;+ set = SetupDiGetClassDevsW( NULL, enumerator, NULL, DIGCF_ALLCLASSES );+ if (INVALID_HANDLE_VALUE == set) goto end;+ devInfo.cbSize = sizeof(devInfo);+ while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))+ if (SetupDiGetDeviceInstanceIdW( set, &devInfo, id, MAX_DEVICE_ID_LEN, NULL )+ && compare_ids( hardware_id, instance_id, id ))+ {+ interfaceData.cbSize = sizeof(interfaceData);+ if (SetupDiCreateDeviceInterfaceW( set, &devInfo,+ InterfaceClassGuid, NULL, 0, &interfaceData ))+ {+ SetupDiGetDeviceInterfaceDetailW( set, &interfaceData, NULL, 0,+ &size, NULL );+ detail = RtlAllocateHeap( GetProcessHeap(), 0, size );+ if (detail == NULL) break;+ detail->cbSize = sizeof(*detail);+ if (!SetupDiGetDeviceInterfaceDetailW( set, &interfaceData,+ detail, size, NULL, NULL ))+ break;+ interf = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*interf) );+ if (interf == NULL) break;+ interf->link = RtlAllocateHeap( GetProcessHeap(), 0,+ (strlenW(detail->DevicePath) + 1) * sizeof(WCHAR) );+ if (interf->link == NULL)+ {+ RtlFreeHeap( GetProcessHeap(), 0, interf );+ break;+ }+ detail->DevicePath[1] = '?';+ strcpyW( interf->link, detail->DevicePath );+ target = RtlAllocateHeap( GetProcessHeap(), 0,+ MAX_PATH * sizeof(WCHAR) );+ if (target == NULL)+ {+ RtlFreeHeap( GetProcessHeap(), 0, interf->link );+ RtlFreeHeap( GetProcessHeap(), 0, interf );+ break;+ }+ status = IoGetDeviceProperty( PhysicalDeviceObject,+ DevicePropertyPhysicalDeviceObjectName,+ MAX_PATH * sizeof(WCHAR), target, &size );+ if (status == STATUS_SUCCESS)+ {+ RtlInitUnicodeString( &interf->target, target );+ interf->guid = *InterfaceClassGuid;

+ interf->active = 0;+ EnterCriticalSection( &cs );+ if (!get_registered_interface( interf->link,+ strlenW(interf->link) ))+ {+ list_add_tail( &Interfaces, &interf->entry );+ LeaveCriticalSection( &cs );+ break;+ }+ LeaveCriticalSection( &cs );+ }+ RtlFreeHeap( GetProcessHeap(), 0, target );+ RtlFreeHeap( GetProcessHeap(), 0, interf->link );+ RtlFreeHeap( GetProcessHeap(), 0, interf );+ }+ break;+ }+ SetupDiDestroyDeviceInfoList( set );++ if (STATUS_SUCCESS == status)+ RtlCreateUnicodeString( SymbolicLinkName, detail->DevicePath );+end:+ if (detail) RtlFreeHeap( GetProcessHeap(), 0, detail );+ if (id) RtlFreeHeap( GetProcessHeap(), 0, id );+ if (enumerator) RtlFreeHeap( GetProcessHeap(), 0, enumerator );+ if (hardware_id) ExFreePool( hardware_id );+ if (instance_id) ExFreePool( instance_id );+ return status;+}++/*********************************************************************** * IoDeleteSymbolicLink (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name )@@ -662,6 +1486,51 @@ NTSTATUS WINAPI IoGetDeviceInterfaces( CONST GUID *InterfaceClassGuid, /***********************************************************************+ * IoSetDeviceInterfaceState (NTOSKRNL.EXE.@)+ */+NTSTATUS WINAPI IoSetDeviceInterfaceState( PUNICODE_STRING SymbolicLinkName,+ BOOLEAN Enable )+{+ TRACE( "%s %d\n", debugstr_us(SymbolicLinkName), Enable );++ if (Enable)+ {+ struct InterfaceInstance *interf;+ NTSTATUS status;+ GUID guid;+ int changed = 0;++ status = STATUS_OBJECT_NAME_NOT_FOUND;+ EnterCriticalSection( &cs );+ interf = get_registered_interface( SymbolicLinkName->Buffer,+ SymbolicLinkName->Length / sizeof(WCHAR) );+ if (interf != NULL)+ {+ if (!interf->active)

+ {+ guid = interf->guid;+ status = IoCreateSymbolicLink( SymbolicLinkName, &interf->target );+ if (status == STATUS_SUCCESS)+ {+ interf->active = 1;+ changed = 1;+ }+ }+ else status = STATUS_SUCCESS;+ }+ LeaveCriticalSection( &cs );+ if (changed) call_interface_change_callbacks( &guid, SymbolicLinkName );+ return status;+ }+ else+ {+ FIXME( "Disabling interface is not supported\n" );+ return STATUS_NOT_IMPLEMENTED;+ }+}+++/*********************************************************************** * IoGetDeviceObjectPointer (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK access, PFILE_OBJECT *file, PDEVICE_OBJECT *device )@@ -677,9 +1546,68 @@ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK acc NTSTATUS WINAPI IoGetDeviceProperty( DEVICE_OBJECT *device, DEVICE_REGISTRY_PROPERTY device_property, ULONG buffer_length, PVOID property_buffer, PULONG result_length ) {- FIXME( "%p %d %u %p %p: stub\n", device, device_property, buffer_length,+ NTSTATUS status;++ TRACE( "%p %d %u %p %p\n", device, device_property, buffer_length, property_buffer, result_length );- return STATUS_NOT_IMPLEMENTED;++ switch (device_property)+ {+ case DevicePropertyHardwareID:+ {+ WCHAR *hardware_id;++ status = get_device_id( device, BusQueryDeviceID, &hardware_id );+ if (status != STATUS_SUCCESS) break;+ *result_length = (strlenW(hardware_id) + 1) * sizeof(WCHAR);+ if (buffer_length >= *result_length)+ strcpyW( property_buffer, hardware_id );+ else+ status = STATUS_BUFFER_TOO_SMALL;+ ExFreePool( hardware_id );+ break;+ }

+ case DevicePropertyPhysicalDeviceObjectName:+ {+ static const WCHAR deviceW[] = {'\\','D','e','v','i','c','e','\\',0};+ WCHAR device_name[MAX_PATH];+ data_size_t len;++ SERVER_START_REQ( get_device_name )+ {+ req->handle = wine_server_obj_handle( device->Reserved );+ wine_server_set_reply( req, device_name,+ sizeof(device_name) - sizeof(WCHAR) );+ status = wine_server_call( req );+ len = wine_server_reply_size( reply );+ }+ SERVER_END_REQ;++ if (status != STATUS_SUCCESS) break;+ *result_length = len + sizeof(deviceW);+ if (buffer_length >= *result_length)+ {+ strcpyW( property_buffer, deviceW );+ device_name[len / sizeof(WCHAR)] = 0;+ strcatW( property_buffer, device_name );+ }+ else status = STATUS_BUFFER_TOO_SMALL;+ break;+ }+ default:+ FIXME( "device property %u is not supported\n", device_property );+ status = STATUS_NOT_IMPLEMENTED;+ }++ return status;+}+++static NTSTATUS WINAPI invalid_request_handler( DEVICE_OBJECT *device, IRP *irp )+{+ irp->IoStatus.u.Status = STATUS_INVALID_DEVICE_REQUEST;+ IoCompleteRequest( irp, IO_NO_INCREMENT );+ return STATUS_INVALID_DEVICE_REQUEST; } @@ -696,9 +1624,21 @@ NTSTATUS WINAPI IoCallDriver( DEVICE_OBJECT *device, IRP *irp ) --irp->CurrentLocation; irpsp = --irp->Tail.Overlay.s.u2.CurrentStackLocation;+ irpsp->DeviceObject = device; dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction];+ if (!dispatch)+ dispatch = invalid_request_handler;++ if (TRACE_ON(relay))+ DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n",+ GetCurrentThreadId(), dispatch, device, irp );+ status = dispatch( device, irp );

+ if (TRACE_ON(relay))+ DPRINTF( "%04x:Ret driver dispatch %p (device=%p,irp=%p) retval=%08x\n",+ GetCurrentThreadId(), dispatch, device, irp, status );+ return status; } @@ -717,6 +1657,14 @@ NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) return IoCallDriver( device, irp ); } +/***********************************************************************+ * IoGetAttachedDeviceReference (NTOSKRNL.EXE.@)+ */+PDEVICE_OBJECT WINAPI IoGetAttachedDeviceReference( PDEVICE_OBJECT obj )+{+ FIXME( "stub: %p\n", obj );+ return obj;+} /*********************************************************************** * IoGetRelatedDeviceObject (NTOSKRNL.EXE.@)@@ -828,6 +1776,97 @@ void WINAPI IoRegisterDriverReinitialization( PDRIVER_OBJECT obj, PDRIVER_REINIT /***********************************************************************+ * IoRegisterPlugPlayNotification (NTOSKRNL.EXE.@)+ */+NTSTATUS WINAPI IoRegisterPlugPlayNotification( IO_NOTIFICATION_EVENT_CATEGORY+ EventCategory,+ ULONG EventCategoryFlags,+ PVOID EventCategoryData,+ PDRIVER_OBJECT DriverObject,+ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE+ CallbackRoutine, PVOID Context,+ PVOID *NotificationEntry )+{+ TRACE( "%u %u %p %p %p %p %p\n", EventCategory, EventCategoryFlags,+ EventCategoryData, DriverObject, CallbackRoutine, Context,+ NotificationEntry );++ if (EventCategory == EventCategoryDeviceInterfaceChange)+ {+ struct InterfaceChangeNotification *notification =+ HeapAlloc( GetProcessHeap(), 0, sizeof(*notification) );+ struct list interfs = LIST_INIT(interfs);+ struct InterfaceInstance *interf, *interf2;+ UNICODE_STRING link;++ if (notification == NULL) return STATUS_NO_MEMORY;+ notification->interface_class = *(GUID *)EventCategoryData;+ notification->callback = CallbackRoutine;+ notification->context = Context;++ EnterCriticalSection( &cs );

+ list_add_tail( &InterfaceChangeNotifications, &notification->entry );+ if (EventCategoryFlags & PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES)+ {+ LIST_FOR_EACH_ENTRY( interf, &Interfaces, struct InterfaceInstance, entry )+ {+ if (interf->active && !memcmp( &notification->interface_class,+ &interf->guid, sizeof(GUID) ))+ {+ interf2 = HeapAlloc( GetProcessHeap(), 0, sizeof(*interf2) );+ if (interf2 == NULL) break;+ interf2->link = HeapAlloc( GetProcessHeap(), 0,+ (strlenW(interf->link) + 1) * sizeof(WCHAR) );+ if (interf2->link == NULL) break;+ strcpyW( interf2->link, interf->link );+ interf2->guid = interf->guid;+ list_add_tail( &interfs, &interf2->entry );+ }+ }+ }+ LeaveCriticalSection( &cs );++ LIST_FOR_EACH_ENTRY_SAFE( interf, interf2, &interfs,+ struct InterfaceInstance, entry )+ {+ list_remove( &interf->entry );+ if (interf->link)+ {+ RtlInitUnicodeString( &link, interf->link );+ call_interface_change_callbacks( &interf->guid, &link );+ HeapFree( GetProcessHeap(), 0, interf->link );+ }+ HeapFree( GetProcessHeap(), 0, interf );+ }+ *NotificationEntry = notification;+ return STATUS_SUCCESS;+ }+ else+ {+ FIXME( "event category %u is not supported\n", EventCategory );+ return STATUS_NOT_IMPLEMENTED;+ }+}+++/***********************************************************************+ * IoUnregisterPlugPlayNotification (NTOSKRNL.EXE.@)+ */+NTSTATUS WINAPI IoUnregisterPlugPlayNotification( PVOID NotificationEntry )+{+ struct InterfaceChangeNotification *notification = NotificationEntry;++ TRACE( "%p\n", NotificationEntry );++ EnterCriticalSection( &cs );+ list_remove( &notification->entry );+ LeaveCriticalSection( &cs );+ HeapFree( GetProcessHeap(), 0, notification );

+ return STATUS_SUCCESS;+}+++/*********************************************************************** * IoRegisterShutdownNotification (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoRegisterShutdownNotification( PDEVICE_OBJECT obj )@@ -869,6 +1908,7 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost ) IO_STATUS_BLOCK *iosb; struct IrpInstance *instance; NTSTATUS status, stat;+ KEVENT *event; int call_flag = 0; TRACE( "%p %u\n", irp, priority_boost );@@ -877,7 +1917,7 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost ) status = irp->IoStatus.u.Status; while (irp->CurrentLocation <= irp->StackCount) {- irpsp = irp->Tail.Overlay.s.u2.CurrentStackLocation;+ irpsp = IoGetCurrentIrpStackLocation( irp ); routine = irpsp->CompletionRoutine; call_flag = 0; /* FIXME: add SL_INVOKE_ON_CANCEL support */@@ -893,28 +1933,47 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost ) if (call_flag) { TRACE( "calling %p( %p, %p, %p )\n", routine,- irpsp->DeviceObject, irp, irpsp->Context );- stat = routine( irpsp->DeviceObject, irp, irpsp->Context );+ (irpsp + 1)->DeviceObject, irp, irpsp->Context );+ stat = routine( (irpsp + 1)->DeviceObject, irp, irpsp->Context ); TRACE( "CompletionRoutine returned %x\n", stat ); if (STATUS_MORE_PROCESSING_REQUIRED == stat) return; } }- if (iosb && STATUS_SUCCESS == status)+ if (iosb && status >= 0) { iosb->u.Status = irp->IoStatus.u.Status; iosb->Information = irp->IoStatus.Information; }+ event = irp->UserEvent;+ EnterCriticalSection( &cs ); LIST_FOR_EACH_ENTRY( instance, &Irps, struct IrpInstance, entry ) { if (instance->irp == irp) {+ void *buf = irp->AssociatedIrp.SystemBuffer;+ MDL *mdl = irp->MdlAddress;+ struct _FILE_OBJECT *file = irp->Tail.Overlay.OriginalFileObject;+ list_remove( &instance->entry ); HeapFree( GetProcessHeap(), 0, instance );+ if (mdl)

+ {+ ExFreePool( mdl );+ }+ else if (buf)+ {+ memcpy( irp->UserBuffer, buf, irp->IoStatus.Information );+ ExFreePool( buf );+ }+ if (file) ExFreePool( file ); IoFreeIrp( irp ); break; } }+ LeaveCriticalSection( &cs );+ if (event)+ KeSetEvent( event, 0, FALSE ); } @@ -1139,12 +2198,40 @@ PRKTHREAD WINAPI KeGetCurrentThread(void) return NULL; } ++/***********************************************************************+ * KeDelayExecutionThread (NTOSKRNL.EXE.@)+ */+NTSTATUS WINAPI KeDelayExecutionThread ( KPROCESSOR_MODE WaitMode,+ BOOLEAN Alertable, PLARGE_INTEGER Interval )+{+ FIXME( "stub: %d %d %p\n", WaitMode, Alertable, Interval );+ return STATUS_SUCCESS;+}++ /*********************************************************************** * KeInitializeEvent (NTOSKRNL.EXE.@) */ void WINAPI KeInitializeEvent( PRKEVENT Event, EVENT_TYPE Type, BOOLEAN State ) {- FIXME( "stub: %p %d %d\n", Event, Type, State );+ TRACE( "%p %d %d\n", Event, Type, State );+ RtlZeroMemory( Event, sizeof(KEVENT) );+ Event->Header.Type = Type;+ Event->Header.Size = 4;+ if (State)+ Event->Header.SignalState = 1;+ InitializeListHead( &Event->Header.WaitListHead );+}+++/***********************************************************************+ * KeClearEvent (NTOSKRNL.EXE.@)+ */+void WINAPI KeClearEvent( PRKEVENT Event )+{+ TRACE( "%p\n", Event );+ InterlockedExchange( &Event->Header.SignalState, 0 ); }

@@ -1153,7 +2240,13 @@ void WINAPI KeInitializeEvent( PRKEVENT Event, EVENT_TYPE Type, BOOLEAN State ) */ void WINAPI KeInitializeMutex(PRKMUTEX Mutex, ULONG Level) {- FIXME( "stub: %p, %u\n", Mutex, Level );+ TRACE( "%p, %u\n", Mutex, Level );+ RtlZeroMemory( Mutex, sizeof(KMUTEX) );+ Mutex->Header.Type = 2;+ Mutex->Header.Size = 8;+ Mutex->Header.SignalState = 1;+ InitializeListHead( &Mutex->Header.WaitListHead );+ Mutex->ApcDisable = 1; } @@ -1174,7 +2267,7 @@ NTSTATUS WINAPI KeWaitForMutexObject(PRKMUTEX Mutex, KWAIT_REASON WaitReason, KP LONG WINAPI KeReleaseMutex(PRKMUTEX Mutex, BOOLEAN Wait) { FIXME( "stub: %p, %d\n", Mutex, Wait );- return STATUS_NOT_IMPLEMENTED;+ return STATUS_SUCCESS; } @@ -1184,6 +2277,8 @@ LONG WINAPI KeReleaseMutex(PRKMUTEX Mutex, BOOLEAN Wait) void WINAPI KeInitializeSemaphore( PRKSEMAPHORE Semaphore, LONG Count, LONG Limit ) { FIXME( "(%p %d %d) stub\n", Semaphore , Count, Limit );+ RtlZeroMemory( Semaphore, sizeof(KSEMAPHORE) );+ Semaphore->Header.Type = 5; } @@ -1202,6 +2297,8 @@ void WINAPI KeInitializeSpinLock( PKSPIN_LOCK SpinLock ) void WINAPI KeInitializeTimerEx( PKTIMER Timer, TIMER_TYPE Type ) { FIXME( "stub: %p %d\n", Timer, Type );+ RtlZeroMemory( Timer, sizeof(KTIMER) );+ Timer->Header.Type = Type ? 9 : 8; } @@ -1294,8 +2391,8 @@ ULONG WINAPI KeQueryTimeIncrement(void) */ LONG WINAPI KeResetEvent( PRKEVENT Event ) {- FIXME("(%p): stub\n", Event);- return 0;+ TRACE("(%p)\n", Event);+ return InterlockedExchange( &Event->Header.SignalState, 0 ); } @@ -1304,8 +2401,23 @@ LONG WINAPI KeResetEvent( PRKEVENT Event ) */ LONG WINAPI KeSetEvent( PRKEVENT Event, KPRIORITY Increment, BOOLEAN Wait )

{- FIXME("(%p, %d, %d): stub\n", Event, Increment, Wait);- return 0;+ struct HandleInstance *inst;+ LONG ret;++ TRACE("(%p, %d, %d)\n", Event, Increment, Wait);++ ret = InterlockedExchange( &Event->Header.SignalState, 1 );+ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry )+ {+ if (inst->object == Event)+ {+ NtSetEvent( inst->handle, NULL );+ break;+ }+ }+ LeaveCriticalSection( &cs );+ return ret; } @@ -1328,8 +2440,84 @@ NTSTATUS WINAPI KeWaitForSingleObject(PVOID Object, BOOLEAN Alertable, PLARGE_INTEGER Timeout) {- FIXME( "stub: %p, %d, %d, %d, %p\n", Object, WaitReason, WaitMode, Alertable, Timeout );- return STATUS_NOT_IMPLEMENTED;+ DISPATCHER_HEADER *header = Object;+ NTSTATUS status = STATUS_SUCCESS;++ TRACE( "%p, %d, %d, %d, %p\n", Object, WaitReason, WaitMode, Alertable, Timeout );++ switch (header->Type)+ {+ case NotificationEvent:+ case SynchronizationEvent:+ {+ struct HandleInstance *inst;+ HANDLE event_handle = NULL;++ if (InterlockedCompareExchange( &header->SignalState, 0, header->Type ))+ {+ status = STATUS_SUCCESS;+ break;+ }++ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry )+ {+ if (inst->object == Object)+ {+ event_handle = inst->handle;+ ++inst->refs;+ break;+ }

+ }+ while (event_handle == NULL)+ {+ OBJECT_ATTRIBUTES attr;++ RtlZeroMemory( &attr, sizeof(attr) );+ attr.Length = sizeof(attr);+ status = NtCreateEvent( &event_handle, EVENT_ALL_ACCESS, &attr,+ !header->Type, FALSE );+ if (status != STATUS_SUCCESS)+ break;+ inst = HeapAlloc( GetProcessHeap(), 0, sizeof(*inst) );+ if (inst == NULL)+ {+ NtClose( event_handle );+ status = STATUS_NO_MEMORY;+ break;+ }+ inst->object = Object;+ inst->handle = event_handle;+ inst->refs = 1;+ list_add_head( &Handles, &inst->entry );+ }+ LeaveCriticalSection( &cs );+ if (status != STATUS_SUCCESS)+ break;++ status = NtWaitForSingleObject( event_handle, Alertable, Timeout );++ EnterCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry )+ {+ if (inst->object == Object)+ {+ if (!--inst->refs)+ {+ list_remove( &inst->entry );+ NtClose( inst->handle );+ HeapFree( GetProcessHeap(), 0, inst );+ }+ break;+ }+ }+ LeaveCriticalSection( &cs );+ break;+ }+ default:+ WARN( "synchronization object %u is not supported\n", header->Type );+ }+ return status; } /***********************************************************************@@ -1427,6 +2615,16 @@ PVOID WINAPI MmMapIoSpace( PHYSICAL_ADDRESS PhysicalAddress, DWORD NumberOfBytes return NULL; } + /***********************************************************************+ * MmMapLockedPages (NTOSKRNL.EXE.@)

+ */+PVOID WINAPI MmMapLockedPages(PMDL MemoryDescriptorList,+ KPROCESSOR_MODE AccessMode)+{+ TRACE("%p %d\n", MemoryDescriptorList, AccessMode);+ return MemoryDescriptorList->MappedSystemVa;+}+ /*********************************************************************** * MmPageEntireDriver (NTOSKRNL.EXE.@) */@@ -1437,6 +2635,16 @@ PVOID WINAPI MmPageEntireDriver(PVOID AddrInSection) } /***********************************************************************+ * MmProbeAndLockPages (NTOSKRNL.EXE.@)+ */+void WINAPI MmProbeAndLockPages(PMDL MemoryDescriptorList,+ KPROCESSOR_MODE AccessMode,+ LOCK_OPERATION Operation)+{+ FIXME("stub: %p %d %u\n", MemoryDescriptorList, AccessMode, Operation);+}++/*********************************************************************** * MmResetDriverPaging (NTOSKRNL.EXE.@) */ void WINAPI MmResetDriverPaging(PVOID AddrInSection)@@ -1489,6 +2697,36 @@ NTSTATUS WINAPI ObReferenceObjectByName( UNICODE_STRING *ObjectName, } /***********************************************************************+ * MmUnmapLockedPages (NTOSKRNL.EXE.@)+ */+void WINAPI MmUnmapLockedPages(PVOID BaseAddress, PMDL MemoryDescriptorList)+{+ TRACE("%p %p\n", BaseAddress, MemoryDescriptorList);+}+++/***********************************************************************+ * ObReferenceObjectByPointer (NTOSKRNL.EXE.@)+ */+NTSTATUS WINAPI ObReferenceObjectByPointer( VOID *obj, ACCESS_MASK access,+ POBJECT_TYPE type,+ KPROCESSOR_MODE mode )+{+ FIXME( "stub: %p %x %p %d\n", obj, access, type, mode );+ return STATUS_NOT_IMPLEMENTED;+}+++/***********************************************************************+ * ObDereferenceObject (NTOSKRNL.EXE.@)+ */+void WINAPI ObDereferenceObject( VOID *obj )+{+ FIXME( "stub: %p\n", obj );+}

+++/*********************************************************************** * ObfDereferenceObject (NTOSKRNL.EXE.@) */ #ifdef DEFINE_FASTCALL1_ENTRYPOINT@@ -1498,11 +2736,19 @@ void WINAPI __regs_ObfDereferenceObject( VOID *obj ) void WINAPI ObfDereferenceObject( VOID *obj ) #endif {- FIXME( "stub: %p\n", obj );+ ObDereferenceObject( obj ); } /***********************************************************************+ * MmUnlockPages (NTOSKRNL.EXE.@)+ */+void WINAPI MmUnlockPages(PMDL MemoryDescriptorList)+{+ FIXME("stub: %p\n", MemoryDescriptorList);+}++/*********************************************************************** * PsCreateSystemThread (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess,@@ -1521,7 +2767,9 @@ NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess, */ HANDLE WINAPI PsGetCurrentProcessId(void) {- if (GetCurrentThreadId() == request_thread)+ DWORD client_pid = get_client_pid();++ if (client_pid) return UlongToHandle(client_pid); return UlongToHandle(GetCurrentProcessId()); }@@ -1532,7 +2780,9 @@ HANDLE WINAPI PsGetCurrentProcessId(void) */ HANDLE WINAPI PsGetCurrentThreadId(void) {- if (GetCurrentThreadId() == request_thread)+ DWORD client_tid = get_client_tid();++ if (client_tid) return UlongToHandle(client_tid); return UlongToHandle(GetCurrentThreadId()); }@@ -1657,10 +2907,10 @@ VOID WINAPI READ_REGISTER_BUFFER_UCHAR(PUCHAR Register, PUCHAR Buffer, ULONG Cou /***************************************************** * PoSetPowerState (NTOSKRNL.EXE.@) */-POWER_STATE WINAPI PoSetPowerState(PDEVICE_OBJECT DeviceObject, POWER_STATE_TYPE Type, POWER_STATE State)+UINT WINAPI PoSetPowerState(PDEVICE_OBJECT DeviceObject, POWER_STATE_TYPE Type, POWER_STATE State) {

FIXME("(%p %u %u) stub\n", DeviceObject, Type, State.DeviceState);- return State;+ return State.DeviceState; } /*****************************************************@@ -1717,6 +2967,8 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { static void *handler; LARGE_INTEGER count;+ struct DriverObjExtension *ext, *ext2;+ struct InterfaceInstance *intf, *intf2; switch(reason) {@@ -1729,6 +2981,22 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) break; case DLL_PROCESS_DETACH: RtlRemoveVectoredExceptionHandler( handler );+ DeleteCriticalSection( &cs );+ LIST_FOR_EACH_ENTRY_SAFE( ext, ext2, &DriverObjExtensions,+ struct DriverObjExtension, entry )+ {+ list_remove( &ext->entry );+ ExFreePool( ext->ptr );+ ExFreePool( ext );+ }+ LIST_FOR_EACH_ENTRY_SAFE( intf, intf2, &Interfaces,+ struct InterfaceInstance, entry )+ {+ list_remove( &intf->entry );+ RtlFreeUnicodeString( &intf->target );+ RtlFreeHeap( GetProcessHeap(), 0, intf->link );+ RtlFreeHeap( GetProcessHeap(), 0, intf );+ } break; } return TRUE;diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.specindex 97a71fc..c79d235 100644--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec@@ -1,4 +1,4 @@-@ stub ExAcquireFastMutexUnsafe+@ stdcall -norelay ExAcquireFastMutexUnsafe(ptr) @ stub ExAcquireRundownProtection @ stub ExAcquireRundownProtectionEx @ stub ExInitializeRundownProtection@@ -8,7 +8,7 @@ @ stub ExInterlockedPopEntrySList @ stub ExInterlockedPushEntrySList @ stub ExReInitializeRundownProtection-@ stub ExReleaseFastMutexUnsafe+@ stdcall -norelay ExReleaseFastMutexUnsafe(ptr) @ stub ExReleaseResourceLite @ stub ExReleaseRundownProtection @ stub ExReleaseRundownProtectionEx

@@ -303,7 +303,7 @@ @ stub InbvSetTextColor @ stub InbvSolidColorFill @ stub InitSafeBootMode-@ stub IoAcquireCancelSpinLock+@ stdcall IoAcquireCancelSpinLock(ptr) @ stub IoAcquireRemoveLockEx @ stub IoAcquireVpbSpinLock @ stub IoAdapterObjectType@@ -356,7 +356,7 @@ @ stdcall IoDeleteDevice(ptr) @ stdcall IoDeleteDriver(ptr) @ stdcall IoDeleteSymbolicLink(ptr)-@ stub IoDetachDevice+@ stdcall IoDetachDevice(ptr) @ stub IoDeviceHandlerObjectSize @ stub IoDeviceHandlerObjectType @ stub IoDeviceObjectType@@ -371,10 +371,10 @@ @ stub IoFreeController @ stub IoFreeErrorLogEntry @ stdcall IoFreeIrp(ptr)-@ stub IoFreeMdl+@ stdcall IoFreeMdl(ptr) @ stub IoFreeWorkItem @ stub IoGetAttachedDevice-@ stub IoGetAttachedDeviceReference+@ stdcall IoGetAttachedDeviceReference(ptr) @ stub IoGetBaseFileSystemDeviceObject @ stub IoGetBootDiskInformation @ stdcall IoGetConfigurationInformation()@@ -400,7 +400,7 @@ @ stdcall IoInitializeIrp(ptr long long) @ stdcall IoInitializeRemoveLockEx(ptr long long long long) @ stdcall IoInitializeTimer(ptr ptr ptr)-@ stub IoInvalidateDeviceRelations+@ stdcall IoInvalidateDeviceRelations(ptr long) @ stub IoInvalidateDeviceState @ stub IoIsFileOriginRemote @ stub IoIsOperationSynchronous@@ -425,14 +425,14 @@ @ stub IoReadPartitionTableEx @ stub IoReadTransferCount @ stub IoRegisterBootDriverReinitialization-@ stub IoRegisterDeviceInterface+@ stdcall IoRegisterDeviceInterface(ptr ptr ptr ptr) @ stdcall IoRegisterDriverReinitialization(ptr ptr ptr) @ stdcall IoRegisterFileSystem(ptr) @ stub IoRegisterFsRegistrationChange @ stub IoRegisterLastChanceShutdownNotification-@ stub IoRegisterPlugPlayNotification+@ stdcall IoRegisterPlugPlayNotification(long long ptr ptr ptr ptr ptr) @ stdcall IoRegisterShutdownNotification(ptr)-@ stub IoReleaseCancelSpinLock+@ stdcall IoReleaseCancelSpinLock(long) @ stub IoReleaseRemoveLockAndWaitEx @ stub IoReleaseRemoveLockEx @ stub IoReleaseVpbSpinLock@@ -446,7 +446,7 @@ @ stub IoRequestDeviceEject

@ stub IoReuseIrp @ stub IoSetCompletionRoutineEx-@ stub IoSetDeviceInterfaceState+@ stdcall IoSetDeviceInterfaceState(ptr long) @ stub IoSetDeviceToVerify @ stub IoSetFileOrigin @ stub IoSetHardErrorOrVerifyDevice@@ -469,7 +469,7 @@ @ stub IoThreadToProcess @ stdcall IoUnregisterFileSystem(ptr) @ stub IoUnregisterFsRegistrationChange-@ stub IoUnregisterPlugPlayNotification+@ stdcall IoUnregisterPlugPlayNotification(ptr) @ stdcall IoUnregisterShutdownNotification(ptr) @ stub IoUpdateShareAccess @ stub IoValidateDeviceIoControlAccess@@ -515,10 +515,10 @@ @ stub KeBugCheckEx @ stub KeCancelTimer @ stub KeCapturePersistentThreadState-@ stub KeClearEvent+@ stdcall KeClearEvent(ptr) @ stub KeConnectInterrupt @ stub KeDcacheFlushCount-@ stub KeDelayExecutionThread+@ stdcall KeDelayExecutionThread(long long ptr) @ stub KeDeregisterBugCheckCallback @ stub KeDeregisterBugCheckReasonCallback @ stub KeDetachProcess@@ -689,7 +689,7 @@ @ stub MmLockPagableImageSection @ stub MmLockPagableSectionByHandle @ stdcall MmMapIoSpace(long long long long)-@ stub MmMapLockedPages+@ stdcall MmMapLockedPages(ptr long) @ stub MmMapLockedPagesSpecifyCache @ stub MmMapLockedPagesWithReservedMapping @ stub MmMapMemoryDumpMdl@@ -702,7 +702,7 @@ @ stub MmMarkPhysicalMemoryAsGood @ stdcall MmPageEntireDriver(ptr) @ stub MmPrefetchPages-@ stub MmProbeAndLockPages+@ stdcall MmProbeAndLockPages(ptr long long) @ stub MmProbeAndLockProcessPages @ stub MmProbeAndLockSelectedPages @ stub MmProtectMdlSystemAddress@@ -717,9 +717,9 @@ @ stub MmSystemRangeStart @ stub MmTrimAllSystemPagableMemory @ stub MmUnlockPagableImageSection-@ stub MmUnlockPages+@ stdcall MmUnlockPages(ptr) @ stdcall MmUnmapIoSpace(ptr long)-@ stub MmUnmapLockedPages+@ stdcall MmUnmapLockedPages(ptr ptr) @ stub MmUnmapReservedMapping @ stub MmUnmapVideoDisplay @ stub MmUnmapViewInSessionSpace@@ -798,7 +798,7 @@

@ stub ObCloseHandle @ stub ObCreateObject @ stub ObCreateObjectType-@ stub ObDereferenceObject+@ stdcall ObDereferenceObject(ptr) @ stub ObDereferenceSecurityDescriptor @ stub ObFindHandleForObject @ stub ObGetObjectSecurity@@ -811,7 +811,7 @@ @ stub ObQueryObjectAuditingByHandle @ stdcall ObReferenceObjectByHandle(long long ptr long ptr ptr) @ stdcall ObReferenceObjectByName(ptr long ptr long ptr long ptr ptr)-@ stub ObReferenceObjectByPointer+@ stdcall ObReferenceObjectByPointer(ptr long ptr long) @ stub ObReferenceSecurityDescriptor @ stub ObReleaseObjectSecurity @ stub ObSetHandleAttributes@@ -1490,3 +1490,9 @@ # or 'wine_' (for user-visible functions) to avoid namespace conflicts. @ cdecl wine_ntoskrnl_main_loop(long)+@ cdecl __wine_add_device(ptr ptr)+@ cdecl __wine_add_driver_object(ptr wstr)+@ cdecl __wine_del_driver_object(ptr)+@ cdecl __wine_get_driver_object(wstr)+@ cdecl __wine_start_device(ptr)+@ cdecl __wine_start_service(wstr)diff --git a/dlls/usbd.sys/usbd.c b/dlls/usbd.sys/usbd.cindex 80fd02e..3b9e86b 100644--- a/dlls/usbd.sys/usbd.c+++ b/dlls/usbd.sys/usbd.c@@ -198,6 +198,15 @@ PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx( return NULL; } +PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptor(+ PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,+ UCHAR InterfaceNumber, UCHAR AlternateSetting )+{+ TRACE( "(%p, %u, %u)\n", ConfigurationDescriptor, InterfaceNumber, AlternateSetting );+ return USBD_ParseConfigurationDescriptorEx( ConfigurationDescriptor, ConfigurationDescriptor,+ InterfaceNumber, AlternateSetting, -1, -1, -1 );+}+ PUSB_COMMON_DESCRIPTOR WINAPI USBD_ParseDescriptors( PVOID DescriptorBuffer, ULONG TotalLength,@@ -214,6 +223,8 @@ PUSB_COMMON_DESCRIPTOR WINAPI USBD_ParseDescriptors( { if (StartPosition <= (PVOID)common && common->bDescriptorType == DescriptorType) return common;+ if (!common->bLength)+ break; } return NULL; }

diff --git a/dlls/usbd.sys/usbd.sys.spec b/dlls/usbd.sys/usbd.sys.specindex 1cb507e..8104baa 100644--- a/dlls/usbd.sys/usbd.sys.spec+++ b/dlls/usbd.sys/usbd.sys.spec@@ -20,7 +20,7 @@ @ stdcall USBD_GetUSBDIVersion(ptr) @ stub USBD_InitializeDevice @ stub USBD_MakePdoName-@ stub USBD_ParseConfigurationDescriptor+@ stdcall USBD_ParseConfigurationDescriptor(ptr long long) @ stdcall _USBD_ParseConfigurationDescriptorEx@28(ptr ptr long long long long long) USBD_ParseConfigurationDescriptorEx @ stdcall _USBD_ParseDescriptors@16(ptr long ptr long) USBD_ParseDescriptors @ stub USBD_QueryBusTimediff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.hindex df58951..f0100f4 100644--- a/include/ddk/ntddk.h+++ b/include/ddk/ntddk.h@@ -127,6 +127,15 @@ typedef struct _IMAGE_INFO ULONG ImageSectionNumber; } IMAGE_INFO, *PIMAGE_INFO; +#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18++#define DO_VERIFY_VOLUME 0x00000002+#define DO_DEVICE_HAS_NAME 0x00000040+#define DO_SYSTEM_BOOT_PARTITION 0x00000100+#define DO_LONG_TERM_REQUESTS 0x00000200+#define DO_NEVER_LAST_DEVICE 0x00000400+#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000+ typedef VOID (WINAPI *PDRIVER_REINITIALIZE)(PDRIVER_OBJECT,PVOID,ULONG); typedef VOID (WINAPI *PLOAD_IMAGE_NOTIFY_ROUTINE)(PUNICODE_STRING,HANDLE,PIMAGE_INFO); typedef NTSTATUS (WINAPI *PIO_QUERY_DEVICE_ROUTINE)(PVOID,PUNICODE_STRING,INTERFACE_TYPE,ULONG,diff --git a/include/ddk/usb100.h b/include/ddk/usb100.hindex b013f21..a85e0b7 100644--- a/include/ddk/usb100.h+++ b/include/ddk/usb100.h@@ -102,6 +102,16 @@ typedef struct _USB_COMMON_DESCRIPTOR { } USB_COMMON_DESCRIPTOR; typedef struct _USB_COMMON_DESCRIPTOR *PUSB_COMMON_DESCRIPTOR; +typedef struct _USB_HUB_DESCRIPTOR {+ UCHAR bDescriptorLength;+ UCHAR bDescriptorType;+ UCHAR bNumberOfPorts;+ USHORT wHubCharacteristics;+ UCHAR bPowerOnToPowerGood;+ UCHAR bHubControlCurrent;+ UCHAR bRemoveAndPowerMask[64];+} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;+ #include <poppack.h> #endifdiff --git a/include/ddk/usbdlib.h b/include/ddk/usbdlib.hindex 0003816..ade33a2 100644--- a/include/ddk/usbdlib.h

+++ b/include/ddk/usbdlib.h@@ -30,6 +30,7 @@ PURB WINAPI USBD_CreateConfigurationRequestEx(PUSB_CONFIGURATION_DESCRIPTOR,PUSB ULONG WINAPI USBD_GetInterfaceLength(PUSB_INTERFACE_DESCRIPTOR,PUCHAR); VOID WINAPI USBD_GetUSBDIVersion(PUSBD_VERSION_INFORMATION); PUSB_COMMON_DESCRIPTOR WINAPI USBD_ParseDescriptors(PVOID,ULONG,PVOID,LONG);+PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR,UCHAR,UCHAR); PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx(PUSB_CONFIGURATION_DESCRIPTOR,PVOID,LONG,LONG,LONG,LONG,LONG); #endifdiff --git a/include/ddk/usbdrivr.h b/include/ddk/usbdrivr.hnew file mode 100644index 0000000..557cbe1--- /dev/null+++ b/include/ddk/usbdrivr.h@@ -0,0 +1,28 @@+/*+ * Copyright 2009 Alexander Morozov for Etersoft+ *+ * 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+ */++#ifndef __USBDRIVR_H__+#define __USBDRIVR_H__++#include <ddk/usbiodef.h>+#include <ddk/usb.h>+#include <ddk/usbdlib.h>++#define IOCTL_INTERNAL_USB_SUBMIT_URB CTL_CODE(FILE_DEVICE_USB, USB_SUBMIT_URB, METHOD_NEITHER, FILE_ANY_ACCESS)++#endif /* __USBDRIVR_H__ */diff --git a/include/ddk/usbioctl.h b/include/ddk/usbioctl.hnew file mode 100644index 0000000..25b2bde--- /dev/null+++ b/include/ddk/usbioctl.h@@ -0,0 +1,97 @@+/*+ * Copyright 2009 Alexander Morozov for Etersoft+ *+ * 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+ */++#ifndef __USBIOCTL_H__+#define __USBIOCTL_H__++#include <ddk/usb100.h>+#include <ddk/usbiodef.h>++#define IOCTL_USB_GET_NODE_INFORMATION CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)+#define IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)++#define IOCTL_USB_GET_ROOT_HUB_NAME CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)++#include <pshpack1.h>++typedef enum _USB_HUB_NODE {+ UsbHub,+ UsbMIParent+} USB_HUB_NODE;++typedef struct _USB_HUB_INFORMATION {+ USB_HUB_DESCRIPTOR HubDescriptor;+ BOOLEAN HubIsBusPowered;+} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;++typedef struct _USB_MI_PARENT_INFORMATION {+ ULONG NumberOfInterfaces;+} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;++typedef struct _USB_NODE_INFORMATION {+ USB_HUB_NODE NodeType;+ union {+ USB_HUB_INFORMATION HubInformation;+ USB_MI_PARENT_INFORMATION MiParentInformation;+ } u;+} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;++typedef struct _USB_PIPE_INFO {+ USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;+ ULONG ScheduleOffset;+} USB_PIPE_INFO, *PUSB_PIPE_INFO;++typedef enum _USB_CONNECTION_STATUS {+ NoDeviceConnected,+ DeviceConnected,+ DeviceFailedEnumeration,

+ DeviceGeneralFailure,+ DeviceCausedOvercurrent,+ DeviceNotEnoughPower,+ DeviceNotEnoughBandwidth,+ DeviceHubNestedTooDeeply,+ DeviceInLegacyHub+} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;++typedef struct _USB_NODE_CONNECTION_INFORMATION {+ ULONG ConnectionIndex;+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;+ UCHAR CurrentConfigurationValue;+ BOOLEAN LowSpeed;+ BOOLEAN DeviceIsHub;+ USHORT DeviceAddress;+ ULONG NumberOfOpenPipes;+ USB_CONNECTION_STATUS ConnectionStatus;+ USB_PIPE_INFO PipeList[0];+} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;++typedef struct _USB_NODE_CONNECTION_DRIVERKEY_NAME {+ ULONG ConnectionIndex;+ ULONG ActualLength;+ WCHAR DriverKeyName[1];+} USB_NODE_CONNECTION_DRIVERKEY_NAME, *PUSB_NODE_CONNECTION_DRIVERKEY_NAME;++typedef struct _USB_HCD_DRIVERKEY_NAME {+ ULONG ActualLength;+ WCHAR DriverKeyName[1];+} USB_HCD_DRIVERKEY_NAME, *PUSB_HCD_DRIVERKEY_NAME;++#include <poppack.h>++#endif /* __USBIOCTL_H__ */diff --git a/include/ddk/usbiodef.h b/include/ddk/usbiodef.hnew file mode 100644index 0000000..dbce800--- /dev/null+++ b/include/ddk/usbiodef.h@@ -0,0 +1,35 @@+/*+ * Copyright 2009 Alexander Morozov for Etersoft+ *+ * 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+ */++#ifndef __USBIODEF_H__+#define __USBIODEF_H__

++#define USB_SUBMIT_URB 0++#define USB_GET_NODE_INFORMATION 258+#define USB_GET_NODE_CONNECTION_INFORMATION 259+#define USB_GET_NODE_CONNECTION_DRIVERKEY_NAME 264++#define HCD_GET_ROOT_HUB_NAME 258++DEFINE_GUID( GUID_DEVINTERFACE_USB_HUB,+ 0xF18A0E88, 0xC30C, 0x11D0, 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 );++#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN++#endif /* __USBIODEF_H__ */diff --git a/include/ddk/wdm.h b/include/ddk/wdm.hindex 85d3da5..5b3cb95 100644--- a/include/ddk/wdm.h+++ b/include/ddk/wdm.h@@ -1092,6 +1092,36 @@ typedef struct _IO_REMOVE_LOCK { IO_REMOVE_LOCK_DBG_BLOCK Dbg; } IO_REMOVE_LOCK, *PIO_REMOVE_LOCK; +typedef enum _LOCK_OPERATION {+ IoReadAccess,+ IoWriteAccess,+ IoModifyAccess+} LOCK_OPERATION;++typedef struct _DEVICE_RELATIONS {+ ULONG Count;+ PDEVICE_OBJECT Objects[1];+} DEVICE_RELATIONS, *PDEVICE_RELATIONS;++typedef enum _IO_NOTIFICATION_EVENT_CATEGORY {+ EventCategoryReserved,+ EventCategoryHardwareProfileChange,+ EventCategoryDeviceInterfaceChange,+ EventCategoryTargetDeviceChange+} IO_NOTIFICATION_EVENT_CATEGORY;++#define PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES 0x00000001++typedef struct _DEVICE_INTERFACE_CHANGE_NOTIFICATION {+ USHORT Version;+ USHORT Size;+ GUID Event;+ GUID InterfaceClassGuid;+ PUNICODE_STRING SymbolicLinkName;+} DEVICE_INTERFACE_CHANGE_NOTIFICATION, *PDEVICE_INTERFACE_CHANGE_NOTIFICATION;++typedef NTSTATUS (WINAPI *PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)(PVOID,PVOID);+ NTSTATUS WINAPI ObCloseHandle(IN HANDLE handle); #ifdef NONAMELESSUNION@@ -1136,6 +1166,7 @@ void WINAPI ExFreePoolWithTag(PVOID,ULONG); NTSTATUS WINAPI IoAllocateDriverObjectExtension(PDRIVER_OBJECT,PVOID,ULONG,PVOID*); PVOID WINAPI IoAllocateErrorLogEntry(PVOID,UCHAR);

PIRP WINAPI IoAllocateIrp(CCHAR,BOOLEAN);+PIRP WINAPI IoBuildDeviceIoControlRequest(ULONG,PDEVICE_OBJECT,PVOID,ULONG,PVOID,ULONG,BOOLEAN,PKEVENT,PIO_STATUS_BLOCK); NTSTATUS WINAPI IoCallDriver(DEVICE_OBJECT*,IRP*); VOID WINAPI IoCompleteRequest(IRP*,UCHAR); NTSTATUS WINAPI IoCreateDevice(DRIVER_OBJECT*,ULONG,UNICODE_STRING*,DEVICE_TYPE,ULONG,BOOLEAN,DEVICE_OBJECT**);@@ -1144,7 +1175,9 @@ NTSTATUS WINAPI IoCreateSymbolicLink(UNICODE_STRING*,UNICODE_STRING*); void WINAPI IoDeleteDevice(DEVICE_OBJECT*); void WINAPI IoDeleteDriver(DRIVER_OBJECT*); NTSTATUS WINAPI IoDeleteSymbolicLink(UNICODE_STRING*);+void WINAPI IoDetachDevice(DEVICE_OBJECT*); void WINAPI IoFreeIrp(IRP*);+PDEVICE_OBJECT WINAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT); PEPROCESS WINAPI IoGetCurrentProcess(void); NTSTATUS WINAPI IoGetDeviceInterfaces(CONST GUID*,PDEVICE_OBJECT,ULONG,PWSTR*); NTSTATUS WINAPI IoGetDeviceObjectPointer(UNICODE_STRING*,ACCESS_MASK,PFILE_OBJECT*,PDEVICE_OBJECT*);@@ -1153,9 +1186,17 @@ PVOID WINAPI IoGetDriverObjectExtension(PDRIVER_OBJECT,PVOID); PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject(PFILE_OBJECT); void WINAPI IoInitializeIrp(IRP*,USHORT,CCHAR); VOID WINAPI IoInitializeRemoveLockEx(PIO_REMOVE_LOCK,ULONG,ULONG,ULONG,ULONG);+void WINAPI IoInvalidateDeviceRelations(PDEVICE_OBJECT,DEVICE_RELATION_TYPE);+NTSTATUS WINAPI IoRegisterDeviceInterface(PDEVICE_OBJECT,CONST GUID*,PUNICODE_STRING,PUNICODE_STRING);+NTSTATUS WINAPI IoRegisterPlugPlayNotification(IO_NOTIFICATION_EVENT_CATEGORY,ULONG,PVOID,PDRIVER_OBJECT,PDRIVER_NOTIFICATION_CALLBACK_ROUTINE,PVOID,PVOID*);+NTSTATUS WINAPI IoSetDeviceInterfaceState(PUNICODE_STRING,BOOLEAN);+NTSTATUS WINAPI IoUnregisterPlugPlayNotification(PVOID); NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT,ULONG); +void WINAPI KeClearEvent(PRKEVENT);+NTSTATUS WINAPI KeDelayExecutionThread(KPROCESSOR_MODE,BOOLEAN,PLARGE_INTEGER); PKTHREAD WINAPI KeGetCurrentThread(void);+void WINAPI KeInitializeEvent(PRKEVENT,EVENT_TYPE,BOOLEAN); void WINAPI KeQuerySystemTime(LARGE_INTEGER*); void WINAPI KeQueryTickCount(LARGE_INTEGER*); ULONG WINAPI KeQueryTimeIncrement(void);@@ -1163,6 +1204,7 @@ LONG WINAPI KeReleaseSemaphore(PRKSEMAPHORE,KPRIORITY,LONG,BOOLEAN); LONG WINAPI KeResetEvent(PRKEVENT); LONG WINAPI KeSetEvent(PRKEVENT,KPRIORITY,BOOLEAN); KPRIORITY WINAPI KeSetPriorityThread(PKTHREAD,KPRIORITY);+NTSTATUS WINAPI KeWaitForSingleObject(PVOID,KWAIT_REASON,KPROCESSOR_MODE,BOOLEAN,PLARGE_INTEGER); PVOID WINAPI MmAllocateContiguousMemory(SIZE_T,PHYSICAL_ADDRESS); PVOID WINAPI MmAllocateNonCachedMemory(SIZE_T);@@ -1170,9 +1212,10 @@ PMDL WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS,PHYSICAL_ADDRESS,PHYSICA void WINAPI MmFreeNonCachedMemory(PVOID,SIZE_T); MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void); +void WINAPI ObDereferenceObject(VOID*);

NTSTATUS WINAPI ObReferenceObjectByHandle(HANDLE,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,PVOID*,POBJECT_HANDLE_INFORMATION);+NTSTATUS WINAPI ObReferenceObjectByPointer(VOID*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE); -POWER_STATE WINAPI PoSetPowerState(PDEVICE_OBJECT,POWER_STATE_TYPE,POWER_STATE); NTSTATUS WINAPI PsCreateSystemThread(PHANDLE,ULONG,POBJECT_ATTRIBUTES,HANDLE,PCLIENT_ID,PKSTART_ROUTINE,PVOID); #define PsGetCurrentProcess() IoGetCurrentProcess() #define PsGetCurrentThread() ((PETHREAD)KeGetCurrentThread())diff --git a/include/ddk/wdmguid.h b/include/ddk/wdmguid.hnew file mode 100644index 0000000..1e21216--- /dev/null+++ b/include/ddk/wdmguid.h@@ -0,0 +1,28 @@+/*+ * Copyright 2009 Alexander Morozov for Etersoft+ *+ * 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+ */++#ifndef __WINE_WDMGUID_H+#define __WINE_WDMGUID_H++DEFINE_GUID(GUID_DEVICE_INTERFACE_ARRIVAL,+0xcb3a4004, 0x46f0, 0x11d0, 0xb0, 0x8f, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3f);++DEFINE_GUID(GUID_DEVICE_INTERFACE_REMOVAL,+0xcb3a4005, 0x46f0, 0x11d0, 0xb0, 0x8f, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3f);++#endif /* __WINE_WDMGUID_H */diff --git a/programs/services/services.c b/programs/services/services.cindex d28e47e..be1e818 100644--- a/programs/services/services.c+++ b/programs/services/services.c@@ -20,6 +20,8 @@ #define WIN32_LEAN_AND_MEAN +#include "config.h"+ #include <stdarg.h> #include <windows.h> #include <winsvc.h>@@ -261,6 +263,11 @@ DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *s

static void scmdatabase_autostart_services(struct scmdatabase *db) {+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)+ static const WCHAR usbhub_started_event[] = {'_','_','w','i','n','e',+ '_','U','s','b','h','u','b','S','t','a','r','t','e','d',0};+ static const WCHAR mountmgr[] = {'M','o','u','n','t','M','g','r',0};+#endif struct service_entry **services_list; unsigned int i = 0; unsigned int size = 32;@@ -298,12 +305,26 @@ static void scmdatabase_autostart_services(struct scmdatabase *db) size = i; for (i = 0; i < size; i++) {+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)+ HANDLE event = NULL;+#endif DWORD err; service = services_list[i];+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)+ if (!strcmpW(service->name, mountmgr))+ event = CreateEventW(NULL, TRUE, FALSE, usbhub_started_event);+#endif err = service_start(service, 0, NULL); if (err != ERROR_SUCCESS) WINE_FIXME("Auto-start service %s failed to start: %d\n", wine_dbgstr_w(service->name), err);+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1)+ else if (event)+ {+ WaitForSingleObject(event, 30000);+ CloseHandle(event);+ }+#endif release_service(service); } diff --git a/programs/winedevice/device.c b/programs/winedevice/device.cindex e48218e..03efa5c 100644--- a/programs/winedevice/device.c+++ b/programs/winedevice/device.c@@ -29,9 +29,8 @@ #include "winbase.h" #include "winternl.h" #include "winreg.h"-#include "winnls.h" #include "winsvc.h"-#include "ddk/wdm.h"+#include "ddk/ntddk.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -39,13 +38,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(winedevice); WINE_DECLARE_DEBUG_CHANNEL(relay); extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );+extern BOOL CDECL __wine_add_driver_object( DRIVER_OBJECT *driver, const WCHAR *service );

+extern void CDECL __wine_del_driver_object( const DRIVER_OBJECT *driver );+extern HANDLE CDECL __wine_make_process_system(void); +#define EVENT_NAME_LEN (30 * sizeof(WCHAR))++static const WCHAR pipe_nameW[] = {'\\','\\','.','\\','p','i','p','e',+ '\\','w','i','n','e','d','e','v','i','c','e',0};+static const WCHAR winedevice_mutexW[] = {'_','_','w','i','n','e','_',+ 'W','i','n','e','d','e','v','i','c','e',0};++/* these variables are used only by "winedevice driver_name" */ static WCHAR *driver_name; static SERVICE_STATUS_HANDLE service_handle;-static HKEY driver_hkey; static HANDLE stop_event;-static DRIVER_OBJECT driver_obj;-static DRIVER_EXTENSION driver_extension; /* find the LDR_MODULE corresponding to the driver module */ static LDR_MODULE *find_ldr_module( HMODULE module )@@ -130,7 +137,9 @@ error: } /* call the driver init entry point */-static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname )+static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname,+ const WCHAR *drv_name, PDRIVER_OBJECT driver_obj,+ PDRIVER_EXTENSION driver_extension ) { unsigned int i; NTSTATUS status;@@ -138,36 +147,38 @@ static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname ) if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; - driver_obj.Size = sizeof(driver_obj);- driver_obj.DriverSection = find_ldr_module( module );- driver_obj.DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);- driver_obj.DriverExtension = &driver_extension;+ driver_obj->Size = sizeof(DRIVER_OBJECT);+ driver_obj->DriverSection = find_ldr_module( module );+ driver_obj->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint);+ driver_obj->DriverExtension = driver_extension; - driver_extension.DriverObject = &driver_obj;- driver_extension.ServiceKeyName = *keyname;+ driver_extension->DriverObject = driver_obj;+ driver_extension->ServiceKeyName = *keyname; if (WINE_TRACE_ON(relay)) WINE_DPRINTF( "%04x:Call driver init %p (obj=%p,str=%s)\n", GetCurrentThreadId(),- driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer) );+ driver_obj->DriverInit, driver_obj, wine_dbgstr_w(keyname

->Buffer) ); - status = driver_obj.DriverInit( &driver_obj, keyname );+ status = driver_obj->DriverInit( driver_obj, keyname ); if (WINE_TRACE_ON(relay)) WINE_DPRINTF( "%04x:Ret driver init %p (obj=%p,str=%s) retval=%08x\n", GetCurrentThreadId(),- driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer), status );+ driver_obj->DriverInit, driver_obj, wine_dbgstr_w(keyname->Buffer), status ); - WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), &driver_obj );- 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( "init done for %s obj %p\n", wine_dbgstr_w(drv_name), driver_obj );+ 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] );+ WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj->MajorFunction[i] ); return status; } /* load the .sys module for a device driver */-static BOOL load_driver(void)+static HMODULE load_driver( const WCHAR *drv_name, PDRIVER_OBJECT driver_obj,+ PDRIVER_EXTENSION driver_extension ) { static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0}; static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0};@@ -180,20 +191,22 @@ static BOOL load_driver(void) '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', '\\','S','e','r','v','i','c','e','s','\\',0}; + HKEY driver_hkey; UNICODE_STRING keypath; HMODULE module; LPWSTR path = NULL, str; DWORD type, size;+ NTSTATUS status; - str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(driver_name)*sizeof(WCHAR) );+ str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(drv_name)*sizeof(WCHAR) ); lstrcpyW( str, servicesW );- lstrcatW( str, driver_name );

+ lstrcatW( str, drv_name ); if (RegOpenKeyW( HKEY_LOCAL_MACHINE, str + 18 /* skip \registry\machine */, &driver_hkey )) { WINE_ERR( "cannot open key %s, err=%u\n", wine_dbgstr_w(str), GetLastError() ); HeapFree( GetProcessHeap(), 0, str);- return FALSE;+ return NULL; } RtlInitUnicodeString( &keypath, str ); @@ -209,7 +222,7 @@ static BOOL load_driver(void) ExpandEnvironmentStringsW(str,path,size); } HeapFree( GetProcessHeap(), 0, str );- if (!path) return FALSE;+ if (!path) return NULL; if (!strncmpiW( path, systemrootW, 12 )) {@@ -235,11 +248,11 @@ static BOOL load_driver(void) WCHAR buffer[MAX_PATH]; GetSystemDirectoryW(buffer, MAX_PATH); path = HeapAlloc(GetProcessHeap(),0,- (strlenW(buffer) + strlenW(driversW) + strlenW(driver_name) + strlenW(postfixW) + 1)+ (strlenW(buffer) + strlenW(driversW) + strlenW(drv_name) + strlenW(postfixW) + 1) *sizeof(WCHAR)); lstrcpyW(path, buffer); lstrcatW(path, driversW);- lstrcatW(path, driver_name);+ lstrcatW(path, drv_name); lstrcatW(path, postfixW); str = path; }@@ -248,10 +261,32 @@ static BOOL load_driver(void) module = load_driver_module( str ); HeapFree( GetProcessHeap(), 0, path );- if (!module) return FALSE;+ if (!module) return NULL; - init_driver( module, &keypath );- return TRUE;+ status = init_driver( module, &keypath, drv_name, driver_obj, driver_extension );+ if (status != STATUS_SUCCESS)+ {+ FreeLibrary( module );+ return NULL;+ }+ return module;+}++static void unload_driver( HMODULE module, DRIVER_OBJECT *driver_obj )+{+ if (driver_obj->DriverUnload)

+ {+ if (WINE_TRACE_ON(relay))+ WINE_DPRINTF( "%04x:Call driver unload %p (obj=%p)\n",+ GetCurrentThreadId(), driver_obj->DriverUnload, driver_obj );++ driver_obj->DriverUnload( driver_obj );++ if (WINE_TRACE_ON(relay))+ WINE_DPRINTF( "%04x:Ret driver unload %p (obj=%p)\n",+ GetCurrentThreadId(), driver_obj->DriverUnload, driver_obj );+ }+ FreeLibrary( module ); } static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )@@ -276,24 +311,144 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_ SetEvent( stop_event ); return NO_ERROR; default:- WINE_FIXME( "got service ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) );+ WINE_FIXME( "got service ctrl %x for %s\n", ctrl,+ wine_dbgstr_w(driver_name) ); status.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( service_handle, &status ); return NO_ERROR; } } +static int loading_request( WCHAR *event_name )+{+ static WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',0};++ WCHAR *driver_process_cmd;+ PROCESS_INFORMATION pi;+ STARTUPINFOW si;+ HANDLE pipe;+ DWORD count, len;+ BOOL ret, loaded;++ /* create winedevice.exe process which will load drivers */++ len = GetSystemDirectoryW( NULL, 0 );+ driver_process_cmd = HeapAlloc( GetProcessHeap(), 0, sizeof(winedeviceW)+ + sizeof(WCHAR) * len );+ if (!driver_process_cmd) return 1;+ GetSystemDirectoryW( driver_process_cmd, len );+ strcpyW( driver_process_cmd + len - 1, winedeviceW );++ RtlZeroMemory( &si, sizeof(STARTUPINFOW) );+ si.cb = sizeof(STARTUPINFOW);+ ret = CreateProcessW( NULL, driver_process_cmd, NULL, NULL, FALSE, 0,+ NULL, NULL, &si, &pi );+ HeapFree( GetProcessHeap(), 0, driver_process_cmd );+ if (!ret) return 1;

+ CloseHandle( pi.hThread );+ CloseHandle( pi.hProcess );++ /* send driver and event names and receive loading result */++ do {+ WaitNamedPipeW( pipe_nameW, NMPWAIT_WAIT_FOREVER );+ pipe = CreateFileW( pipe_nameW, GENERIC_READ | GENERIC_WRITE, 0, NULL,+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );+ } while (pipe == INVALID_HANDLE_VALUE);+ len = (strlenW(driver_name) + 1) * sizeof(WCHAR);+ ret = WriteFile( pipe, &len, sizeof(DWORD), &count, NULL );+ if (!ret || count != sizeof(DWORD)) goto fail;+ ret = WriteFile( pipe, driver_name, len, &count, NULL );+ if (!ret || count != len) goto fail;+ ret = WriteFile( pipe, event_name, EVENT_NAME_LEN, &count, NULL );+ if (!ret || count != EVENT_NAME_LEN) goto fail;+ ret = ReadFile( pipe, &loaded, sizeof(BOOL), &count, NULL );+ if (!ret || count != sizeof(BOOL)) goto fail;+ if (loaded)+ {+ CloseHandle( pipe );+ return 0;+ }+fail:+ CloseHandle( pipe );+ return 1;+}++static HMODULE handle_loading_request( HANDLE pipe, DRIVER_OBJECT *driver_obj,+ DRIVER_EXTENSION *driver_extension,+ WCHAR **drv_name, WCHAR **event_name )+{+ HMODULE module = NULL;+ BOOL ret, loaded = FALSE;+ DWORD count, len;++ *drv_name = NULL;+ *event_name = NULL;+ ret = ReadFile( pipe, &len, sizeof(DWORD), &count, NULL );+ if (!ret || count != sizeof(DWORD)) goto end;+ *drv_name = HeapAlloc( GetProcessHeap(), 0, len );+ if (!*drv_name) goto end;+ ret = ReadFile( pipe, *drv_name, len, &count, NULL );+ if (!ret || count != len) goto end;+ *event_name = HeapAlloc( GetProcessHeap(), 0, EVENT_NAME_LEN );+ if (!*event_name) goto end;+ ret = ReadFile( pipe, *event_name, EVENT_NAME_LEN, &count, NULL );+ if (!ret || count != EVENT_NAME_LEN) goto end;+ module = load_driver( *drv_name, driver_obj, driver_extension );+ if (module) loaded = TRUE;+ ret = WriteFile( pipe, &loaded, sizeof(BOOL), &count, NULL );+ if (module && (!ret || count != sizeof(BOOL)))+ {+ unload_driver( module, driver_obj );+ module = NULL;+ }+end:+ DisconnectNamedPipe( pipe );+ CloseHandle( pipe );

+ if (!module)+ {+ if (*drv_name) HeapFree( GetProcessHeap(), 0, *drv_name );+ if (*event_name) HeapFree( GetProcessHeap(), 0, *drv_name );+ }+ return module;+}++static HANDLE create_named_event( WCHAR **event_name )+{+ static const WCHAR event_nameW[] = {'_','_','w','i','n','e','_',+ 'W','i','n','e','d','e','v','i','c','e','_','%','u',0};++ HANDLE event;+ unsigned int k = 0;++ *event_name = HeapAlloc( GetProcessHeap(), 0, EVENT_NAME_LEN );+ if (!*event_name) return NULL;+ for (;;)+ {+ snprintfW( *event_name, EVENT_NAME_LEN / sizeof(WCHAR), event_nameW, k++ );+ event = CreateEventW( NULL, TRUE, FALSE, *event_name );+ if (event && GetLastError() != ERROR_ALREADY_EXISTS)+ return event;+ CloseHandle( event );+ }+}+ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) { SERVICE_STATUS status;+ WCHAR *event_name; WINE_TRACE( "starting service %s\n", wine_dbgstr_w(driver_name) ); - stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );-+ stop_event = create_named_event( &event_name );+ if (!stop_event)+ return; service_handle = RegisterServiceCtrlHandlerExW( driver_name, service_handler, NULL ); if (!service_handle)+ {+ HeapFree( GetProcessHeap(), 0, event_name ); return;+ } status.dwServiceType = SERVICE_WIN32; status.dwCurrentState = SERVICE_START_PENDING;@@ -304,31 +459,100 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) status.dwWaitHint = 10000; SetServiceStatus( service_handle, &status ); - if (load_driver())+ if (!loading_request( event_name )) {

status.dwCurrentState = SERVICE_RUNNING; status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; SetServiceStatus( service_handle, &status ); - wine_ntoskrnl_main_loop( stop_event );+ WaitForSingleObject( stop_event, INFINITE ); } else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) ); + HeapFree( GetProcessHeap(), 0, event_name ); status.dwCurrentState = SERVICE_STOPPED; status.dwControlsAccepted = 0; SetServiceStatus( service_handle, &status ); WINE_TRACE( "service %s stopped\n", wine_dbgstr_w(driver_name) ); } -int wmain( int argc, WCHAR *argv[] )+static DWORD CALLBACK driver_thread( HANDLE pipe ) {- SERVICE_TABLE_ENTRYW service_table[2];+ DRIVER_OBJECT driver_obj;+ DRIVER_EXTENSION driver_extension;+ WCHAR *drv_name, *event_name;+ HMODULE module; - if (!(driver_name = argv[1]))+ RtlZeroMemory( &driver_obj, sizeof(driver_obj) );+ RtlZeroMemory( &driver_extension, sizeof(driver_extension) );+ module = handle_loading_request( pipe, &driver_obj, &driver_extension,+ &drv_name, &event_name );+ if (module) {- WINE_ERR( "missing device name, winedevice isn't supposed to be run manually\n" );+ HANDLE loop_event;++ loop_event = CreateEventW( NULL, TRUE, FALSE, event_name );+ if (__wine_add_driver_object( &driver_obj, drv_name ))+ {+ wine_ntoskrnl_main_loop( loop_event );+ __wine_del_driver_object( &driver_obj );+ }+ /* stop service if wine_ntoskrnl_main_loop exits */+ SetEvent( loop_event );+ CloseHandle( loop_event );+ unload_driver( module, &driver_obj );+ HeapFree( GetProcessHeap(), 0, drv_name );+ HeapFree( GetProcessHeap(), 0, event_name );+ }+ return 0;+}++static int driver_process(void)+{+ HANDLE pipe, winedevice_mutex, thread;++ __wine_make_process_system();+ winedevice_mutex = CreateMutexW( NULL, TRUE, winedevice_mutexW );+ if (GetLastError() == ERROR_ALREADY_EXISTS)

+ {+ CloseHandle( winedevice_mutex ); return 1; }+ for (;;)+ {+ pipe = CreateNamedPipeW( pipe_nameW, PIPE_ACCESS_DUPLEX,+ PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,+ 256, 256, 10000, NULL );+ if (pipe == INVALID_HANDLE_VALUE)+ {+ WINE_ERR( "failed to create pipe\n" );+ continue;+ }+ if (!ConnectNamedPipe( pipe, NULL ) &&+ GetLastError() != ERROR_PIPE_CONNECTED)+ {+ CloseHandle( pipe );+ continue;+ }++ thread = CreateThread( NULL, 0, driver_thread, pipe, 0, NULL );+ if (!thread)+ {+ WINE_ERR( "failed to create thread\n" );+ DisconnectNamedPipe( pipe );+ CloseHandle( pipe );+ continue;+ }+ CloseHandle( thread );+ }+}++int wmain( int argc, WCHAR *argv[] )+{+ SERVICE_TABLE_ENTRYW service_table[2];++ if (!argv[1]) return driver_process();+ driver_name = argv[1]; service_table[0].lpServiceName = argv[1]; service_table[0].lpServiceProc = ServiceMain;diff --git a/server/device.c b/server/device.cindex 49f90e3..1d6a015 100644--- a/server/device.c+++ b/server/device.c@@ -557,3 +557,26 @@ DECL_HANDLER(get_ioctl_result) } release_object( device ); }+++/* get a device name */+DECL_HANDLER(get_device_name)+{+ struct device *device;+ const WCHAR *device_name;+ data_size_t device_name_len;++ if (!(device = (struct device *)get_handle_obj( current->process, req->hand

le, 0, &device_ops )))+ return;++ if ((device_name = get_object_name( &device->obj, &device_name_len )))+ {+ if (device_name_len <= get_reply_max_size())+ set_reply_data( device_name, device_name_len );+ else+ set_error( STATUS_BUFFER_TOO_SMALL );+ }+ else set_error( STATUS_INVALID_DEVICE_REQUEST );++ release_object( device );+}diff --git a/server/protocol.def b/server/protocol.defindex 33cbb30..b1126bf 100644--- a/server/protocol.def+++ b/server/protocol.def@@ -3376,3 +3376,11 @@ enum coords_relative @REQ(set_suspend_context) VARARG(context,context); /* thread context */ @END+++/* Get a device name */+@REQ(get_device_name)+ obj_handle_t handle; /* device handle */+@REPLY+ VARARG(name,unicode_str); /* device name */+@END-- 1.7.10.5