Sei sulla pagina 1di 94

From cb189424b13c5e166bef9acc487c4353c830a10c Mon Sep 17 00:00:00 2001

From: Alexander Morozov <amorozov@etersoft.ru>


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 ****

+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 dyn
amic 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 a
nd 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 lib
rary 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"
then
diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in
index 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.c
index 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.subsyste
m", 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_VO
L, 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 ch
ar *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.c
index 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.c
index 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.h


index 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_HID
DEN;
+
/* device functions */
enum device_type
@@ -71,3 +74,8 @@ extern struct mount_point *add_volume_mount_point( DEVICE_OBJE
CT *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, unsi
gned 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.c
new file mode 100644
index 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, UL
ONG 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.SystemBuff
er,
+
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->Interfa
ce;
+
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].bEndpointAdd
ress +
+
((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 =

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
R)) ?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
nf ))
+
+
+
+
+
gth );
+
+
+
+
+
+
+
+

&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_DESCRIPTO
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, &co
break;
add_data( &buf, &size, conf,
sizeof(USB_CONFIGURATION_DESCRIPTOR) );
if (size > 0 && conf->extra)
add_data( &buf, &size, conf->extra, conf->extra_len
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(USHOR
T))
+
{
+
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;

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
;
+
;
+
;
+
;
+
;
+
;
+
+
+
+
+
+
)
+
+
+
x,
+
+
+

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->Inde
buf, size, 0 );
if (ret >= 0)
{

+
if (request->TransferFlags & USBD_TRANSFER_DIRECTIO
N_IN)
+
{
+
request->TransferBufferLength =
+
(ret < size) ? ret : size;
+
memcpy( req_buf, buf, request->TransferBufferLe
ngth );
+
}
+
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.ConfigurationDescript
or;
+
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->Interfa
ce;
+
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.bNumConfiguration
s; ++n)

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ress +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

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].bEndpointAdd
((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->PipeHandl
e & 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;

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[0];
+
+
+
+
+
+
+
+
+
);
+
+
+
+
+
+
+
+
len );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

}
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
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->extra
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" );
{

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
T))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

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(USHOR
{
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_DIRECTIO
N_IN)
+
{
+
request->TransferBufferLength =
+
(ret < size) ? ret : size;
+
memcpy( req_buf, buf, request->TransferBufferLe
ngth );
+
}
+
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 h
ubs\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_le
n ||
+
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, en
try )
+
{
+
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, ent
ry )
+
{
+
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, en
try )
+
{
+
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_dev
ice" );
+
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 *pat
h )
+{
+#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_ioc
tl;
+
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.in
index 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.c
index 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(InterfaceChangeNoti
fications);
+
+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_HARDWAREI
D,
+
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 lis
t */
+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_DEVI
CE_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( i
n_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 *servic
e )
+{
+
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_O
BJECT DriverObject,
ULONG DriverObjectExtensionSiz
e,
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_O
BJECT 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, UCHA
R EntrySize )
*/
PMDL WINAPI IoAllocateMdl( PVOID VirtualAddress, ULONG Length, BOOLEAN Secondar
yBuffer, BOOLEAN ChargeQuota, PIRP Irp )
{
FIXME( "stub: %p, %u, %i, %i, %p\n", VirtualAddress, Length, SecondaryBuffe
r, 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_OB
JECT *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 IoControlC
ode,
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 IoContro
lCode,
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, InputBuffe
rLength ) );
+
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(
if (instance == NULL)
goto err;
instance->irp = irp;
EnterCriticalSection(
list_add_tail( &Irps,
LeaveCriticalSection(

GetProcessHeap(), 0, sizeof(struct IrpInstance) );

&cs );
&instance->entry );
&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, ULON
G ext_size,
DEVICE_OBJECT *device;
HANDLE handle = 0;
HANDLE manager = get_device_manager();
+
UNICODE_STRING generated_name;

e,
@@
NG
e)
+
+
+
+
+
+
+
+
+
+
+

TRACE( "(%p, %u, %s, %u, %x, %u, %p)\n",


driver, ext_size, debugstr_us(name), type, characteristics, exclusiv
ret_device );
-539,6 +1164,17 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULO
ext_size,
if (!(device = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*devic
+ 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, ULO
NG 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, ULON
G 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 *nam


e, 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, &servi
ce )
+
&& __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]->AttachedDevic
e );
+
}
+
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_i
d );

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
NULL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

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,
)
&& 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 *Interfa
ceClassGuid,
/***********************************************************************
+ *
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->targe
t );
+
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 ac
cess, 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_PRO
PERTY 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_OBJE
CT obj, PDRIVER_REINIT
/***********************************************************************
+ *
IoRegisterPlugPlayNotification
(NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI IoRegisterPlugPlayNotification( IO_NOTIFICATION_EVENT_CATEGORY
+
EventCategory,
+
ULONG EventCategoryFlags,
+
PVOID EventCategoryData,
+
PDRIVER_OBJECT DriverObject,
+
PDRIVER_NOTIFICATION_CALLBACK_R
OUTINE
+
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_IN
TERFACES)
+
{
+
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_boo
st )
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_boo
st )
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_b
oost )
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 Lim
it )
{
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, Alertabl
e, Timeout );
return STATUS_NOT_IMPLEMENTED;
+
DISPATCHER_HEADER *header = Object;
+
NTSTATUS status = STATUS_SUCCESS;
+
+
TRACE( "%p, %d, %d, %d, %p\n", Object, WaitReason, WaitMode, Alertable, Tim
eout );
+
+
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 PhysicalAddre
ss, 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_TYP
E 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.ex
e.spec
index 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.c
index 80fd02e..3b9e86b 100644
--- a/dlls/usbd.sys/usbd.c
+++ b/dlls/usbd.sys/usbd.c
@@ -198,6 +198,15 @@ PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDes
criptorEx(
return NULL;
}
+PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptor(
+
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+
UCHAR InterfaceNumber, UCHAR AlternateSetting )
+{
+
TRACE( "(%p, %u, %u)\n", ConfigurationDescriptor, InterfaceNumber, Alternat
eSetting );
+
return USBD_ParseConfigurationDescriptorEx( ConfigurationDescriptor, Config
urationDescriptor,
+
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 == Descri
ptorType)
return common;
+
if (!common->bLength)
+
break;
}
return NULL;
}

diff --git a/dlls/usbd.sys/usbd.sys.spec b/dlls/usbd.sys/usbd.sys.spec


index 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 l
ong) USBD_ParseConfigurationDescriptorEx
@ stdcall _USBD_ParseDescriptors@16(ptr long ptr long) USBD_ParseDescriptors
@ stub USBD_QueryBusTime
diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h
index 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,INTER
FACE_TYPE,ULONG,
diff --git a/include/ddk/usb100.h b/include/ddk/usb100.h
index 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>
#endif
diff --git a/include/ddk/usbdlib.h b/include/ddk/usbdlib.h
index 0003816..ade33a2 100644
--- a/include/ddk/usbdlib.h

+++ b/include/ddk/usbdlib.h
@@ -30,6 +30,7 @@ PURB WINAPI USBD_CreateConfigurationRequestEx(PUSB_CONFIGURATI
ON_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_CONFIGU
RATION_DESCRIPTOR,UCHAR,UCHAR);
PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx(PUSB_CONFI
GURATION_DESCRIPTOR,PVOID,LONG,LONG,LONG,LONG,LONG);
#endif
diff --git a/include/ddk/usbdrivr.h b/include/ddk/usbdrivr.h
new file mode 100644
index 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.h
new file mode 100644
index 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.h
new file mode 100644
index 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.h
index 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,PVO
ID*);
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_TYP
E,ULONG,BOOLEAN,DEVICE_OBJECT**);
@@ -1144,7 +1175,9 @@ NTSTATUS WINAPI IoCreateSymbolicLink(UNICODE_STRING*,UNIC
ODE_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_OBJ
ECT*,PDEVICE_OBJECT*);
@@ -1153,9 +1186,17 @@ PVOID
WINAPI IoGetDriverObjectExtension(PDRIVER_OBJEC
T,PVOID);
PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject(PFILE_OBJECT);
void
WINAPI IoInitializeIrp(IRP*,USHORT,CCHAR);
VOID
WINAPI IoInitializeRemoveLockEx(PIO_REMOVE_LOCK,ULONG,ULONG,ULONG,ULO
NG);
+void
WINAPI IoInvalidateDeviceRelations(PDEVICE_OBJECT,DEVICE_RELATION_TYP
E);
+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,BOOLE
AN,PLARGE_INTEGER);
PVOID
WINAPI MmAllocateContiguousMemory(SIZE_T,PHYSICAL_ADDRESS);
PVOID
WINAPI MmAllocateNonCachedMemory(SIZE_T);
@@ -1170,9 +1212,10 @@ PMDL
WINAPI MmAllocatePagesForMdl(PHYSICAL_ADDRESS,P
HYSICAL_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,KPRO


CESSOR_MODE,PVOID*,POBJECT_HANDLE_INFORMATION);
+NTSTATUS WINAPI ObReferenceObjectByPointer(VOID*,ACCESS_MASK,POBJECT_TYPE,KPRO
CESSOR_MODE);
-POWER_STATE WINAPI PoSetPowerState(PDEVICE_OBJECT,POWER_STATE_TYPE,POWER_STATE)
;
NTSTATUS WINAPI PsCreateSystemThread(PHANDLE,ULONG,POBJECT_ATTRIBUTES,HANDLE,P
CLIENT_ID,PKSTART_ROUTINE,PVOID);
#define
PsGetCurrentProcess() IoGetCurrentProcess()
#define
PsGetCurrentThread() ((PETHREAD)KeGetCurrentThread())
diff --git a/include/ddk/wdmguid.h b/include/ddk/wdmguid.h
new file mode 100644
index 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.c
index 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, st
ruct 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 scmdatab
ase *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.c
index 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_STRIN
G *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->Opti
onalHeader.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->Opt
ionalHeader.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", GetCurrentT
hreadId(),
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), &drive
r_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_ob
j );
+
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_na


me)*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), GetLastEr
ror() );
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(po
stfixW) + 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_extens
ion );
+
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, drive
r_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, drive
r_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 ev
ent_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) );
+
+
+
r,
+
+
+

stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );


stop_event = create_named_event( &event_name );
if (!stop_event)
return;
service_handle = RegisterServiceCtrlHandlerExW( driver_name, service_handle
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_SHUTDO
WN;
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 man
ually\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)

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+int
+{
+
+
+
+

{
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 );
}
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.c
index 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.def
index 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

Potrebbero piacerti anche