From e671ba3294a646eab5831ef25c89abea74f6b25b Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Mon, 16 Mar 2009 14:36:44 +0300 Subject: [PATCH 1/2] Add support of native Windows drivers for USB tokens. --- configure.ac | 14 + dlls/hal/hal.c | 6 + dlls/hal/hal.spec | 2 +- dlls/mountmgr.sys/device.c | 19 +- dlls/mountmgr.sys/mountmgr.c | 76 ++- dlls/ntoskrnl.exe/Makefile.in | 2 +- dlls/ntoskrnl.exe/ntoskrnl.c | 1275 +++++++++++++++++++++++++++++++++-- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 62 +- dlls/usbd.sys/Makefile.in | 15 + dlls/usbd.sys/usbd.c | 145 ++++ dlls/usbd.sys/usbd.sys.spec | 35 + dlls/usbhub.sys/Makefile.in | 15 + dlls/usbhub.sys/usbhub.c | 551 +++++++++++++++ dlls/usbhub.sys/usbhub.sys.spec | 1 + include/cfgmgr32.h | 1 + include/ddk/ntddk.h | 11 + include/ddk/usb.h | 6 + include/ddk/usbdrivr.h | 28 + include/ddk/usbiodef.h | 26 + include/ddk/wdm.h | 53 ++ programs/winedevice/device.c | 302 +++++++-- server/device.c | 25 + server/protocol.def | 9 + tools/wine.inf.in | 9 + 24 files changed, 2523 insertions(+), 165 deletions(-) create mode 100644 dlls/usbd.sys/Makefile.in create mode 100644 dlls/usbd.sys/usbd.c create mode 100644 dlls/usbd.sys/usbd.sys.spec create mode 100644 dlls/usbhub.sys/Makefile.in create mode 100644 dlls/usbhub.sys/usbhub.c create mode 100644 dlls/usbhub.sys/usbhub.sys.spec create mode 100644 include/ddk/usbdrivr.h create mode 100644 include/ddk/usbiodef.h diff --git a/configure.ac b/configure.ac index 3c2463c..7de1928 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,7 @@ AC_ARG_WITH(png, AS_HELP_STRING([--without-png],[do not use PNG]), AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthread library]), [if test "x$withval" = "xno"; then ac_cv_header_pthread_h=no; fi]) AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)])) +AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use USB])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]), @@ -359,6 +360,7 @@ AC_CHECK_HEADERS(\ syscall.h \ termios.h \ unistd.h \ + usb.h \ utime.h \ valgrind/memcheck.h \ valgrind/valgrind.h @@ -1031,6 +1033,18 @@ fi WINE_NOTICE_WITH(sane,[test "x$ac_cv_lib_soname_sane" = "x"], [libsane ${notice_platform}development files not found, scanners won't be supported.]) +dnl **** Check for LIBUSB **** +AC_SUBST(USBLIBS,"") +if test "$ac_cv_header_usb_h" = "yes" -a "x$with_usb" != "xno" +then + AC_CHECK_LIB(usb, usb_init, + [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb library and header]) + USBLIBS="-lusb"]) +fi +WINE_NOTICE_WITH(usb,[test "$ac_cv_lib_usb_usb_init" != "yes"], + [libusb ${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/hal/hal.c b/dlls/hal/hal.c index 82ba80c..5d8d9f8 100644 --- a/dlls/hal/hal.c +++ b/dlls/hal/hal.c @@ -126,3 +126,9 @@ ULONG WINAPI HalGetBusData(BUS_DATA_TYPE BusDataType, ULONG BusNumber, ULONG Slo /* Claim that there is no such bus */ return 0; } + +KIRQL WINAPI KeGetCurrentIrql(void) +{ + FIXME( "stub!\n" ); + return 0; +} diff --git a/dlls/hal/hal.spec b/dlls/hal/hal.spec index 83eedea..13f9717 100644 --- a/dlls/hal/hal.spec +++ b/dlls/hal/hal.spec @@ -70,7 +70,7 @@ @ stub KdComPortInUse @ stub KeAcquireSpinLock @ stub KeFlushWriteBuffer -@ stub KeGetCurrentIrql +@ stdcall KeGetCurrentIrql() @ stub KeLowerIrql @ stub KeQueryPerformanceCounter @ stub KeRaiseIrql diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c index 0467079..0639aa9 100644 --- a/dlls/mountmgr.sys/device.c +++ b/dlls/mountmgr.sys/device.c @@ -39,6 +39,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); +extern void CDECL wine_complete_request( IRP *irp, UCHAR priority_boost ); + #define MAX_DOS_DRIVES 26 static const WCHAR drive_types[][8] = @@ -605,6 +607,7 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; struct dos_drive *drive = device->DeviceExtension; + NTSTATUS status; TRACE( "ioctl %x insize %u outsize %u\n", irpsp->Parameters.DeviceIoControl.IoControlCode, @@ -623,29 +626,31 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) info.TracksPerCylinder = 255; info.SectorsPerTrack = 63; info.BytesPerSector = 512; - memcpy( irp->MdlAddress->StartVa, &info, len ); + memcpy( irp->AssociatedIrp.SystemBuffer, &info, len ); irp->IoStatus.Information = len; - irp->IoStatus.u.Status = STATUS_SUCCESS; + status = STATUS_SUCCESS; break; } case IOCTL_STORAGE_GET_DEVICE_NUMBER: { DWORD len = min( sizeof(drive->devnum), irpsp->Parameters.DeviceIoControl.OutputBufferLength ); - memcpy( irp->MdlAddress->StartVa, &drive->devnum, len ); + memcpy( irp->AssociatedIrp.SystemBuffer, &drive->devnum, len ); irp->IoStatus.Information = len; - irp->IoStatus.u.Status = STATUS_SUCCESS; + status = STATUS_SUCCESS; break; } case IOCTL_CDROM_READ_TOC: - irp->IoStatus.u.Status = STATUS_INVALID_DEVICE_REQUEST; + status = STATUS_INVALID_DEVICE_REQUEST; break; default: FIXME( "unsupported ioctl %x\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); - irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + status = STATUS_NOT_SUPPORTED; break; } - return irp->IoStatus.u.Status; + irp->IoStatus.u.Status = status; + wine_complete_request( irp, IO_NO_INCREMENT ); + return status; } /* driver entry point for the harddisk driver */ diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index 00112b9..04baba1 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -33,6 +33,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); +extern void CDECL wine_complete_request( IRP *irp, UCHAR priority_boost ); + #define MIN_ID_LEN 4 struct mount_point @@ -352,6 +354,7 @@ static NTSTATUS query_unix_drive( const void *in_buff, SIZE_T insize, static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; + NTSTATUS status; TRACE( "ioctl %x insize %u outsize %u\n", irpsp->Parameters.DeviceIoControl.IoControlCode, @@ -361,36 +364,71 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp ) switch(irpsp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_MOUNTMGR_QUERY_POINTS: - if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT)) - return STATUS_INVALID_PARAMETER; - irp->IoStatus.u.Status = query_mount_points( irpsp->Parameters.DeviceIoControl.Type3InputBuffer, - irpsp->Parameters.DeviceIoControl.InputBufferLength, - irp->MdlAddress->StartVa, - irpsp->Parameters.DeviceIoControl.OutputBufferLength, - &irp->IoStatus ); + { + void *in_buff; + ULONG in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength; + + if (in_size < sizeof(MOUNTMGR_MOUNT_POINT)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + in_buff = ExAllocatePool( NonPagedPool, in_size ); + if (!in_buff) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + memcpy( in_buff, irp->AssociatedIrp.SystemBuffer, in_size ); + status = query_mount_points( in_buff, in_size, + irp->AssociatedIrp.SystemBuffer, + irpsp->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + ExFreePool( in_buff ); break; + } case IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE: if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_unix_drive)) - return STATUS_INVALID_PARAMETER; + { + status = STATUS_INVALID_PARAMETER; + break; + } irp->IoStatus.Information = 0; - irp->IoStatus.u.Status = define_unix_drive( irpsp->Parameters.DeviceIoControl.Type3InputBuffer, - irpsp->Parameters.DeviceIoControl.InputBufferLength ); + status = define_unix_drive( irp->AssociatedIrp.SystemBuffer, + irpsp->Parameters.DeviceIoControl.InputBufferLength ); break; case IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE: - if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_unix_drive)) - return STATUS_INVALID_PARAMETER; - irp->IoStatus.u.Status = query_unix_drive( irpsp->Parameters.DeviceIoControl.Type3InputBuffer, - irpsp->Parameters.DeviceIoControl.InputBufferLength, - irp->MdlAddress->StartVa, - irpsp->Parameters.DeviceIoControl.OutputBufferLength, - &irp->IoStatus ); + { + void *in_buff; + ULONG in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength; + + if (in_size < sizeof(struct mountmgr_unix_drive)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + in_buff = ExAllocatePool( NonPagedPool, in_size ); + if (!in_buff) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + memcpy( in_buff, irp->AssociatedIrp.SystemBuffer, in_size ); + status = query_unix_drive( in_buff, in_size, + irp->AssociatedIrp.SystemBuffer, + irpsp->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + ExFreePool( in_buff ); break; + } default: FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); - irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + status = STATUS_NOT_SUPPORTED; break; } - return irp->IoStatus.u.Status; + irp->IoStatus.u.Status = status; + wine_complete_request( irp, IO_NO_INCREMENT ); + return status; } /* main entry point for the mount point manager driver */ diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in index 0dad8c3..d6d8540 100644 --- a/dlls/ntoskrnl.exe/Makefile.in +++ b/dlls/ntoskrnl.exe/Makefile.in @@ -4,7 +4,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = ntoskrnl.exe IMPORTLIB = ntoskrnl.exe -IMPORTS = kernel32 ntdll +IMPORTS = kernel32 ntdll setupapi advapi32 C_SRCS = \ ntoskrnl.c diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 6371d85..60980c0 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -30,6 +30,13 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winternl.h" +#include "winioctl.h" +#include "winbase.h" +#include "winsvc.h" +#include "winuser.h" +#include "winreg.h" +#include "setupapi.h" +#include "cfgmgr32.h" #include "excpt.h" #include "ddk/ntddk.h" #include "wine/unicode.h" @@ -56,6 +63,8 @@ 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 struct list Irps = LIST_INIT(Irps); struct IrpInstance @@ -64,6 +73,46 @@ struct IrpInstance IRP *irp; }; +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 process_id; +}; + +static struct list Interfaces = LIST_INIT(Interfaces); + +struct InterfaceInstance +{ + struct list entry; + WCHAR *link; + UNICODE_STRING target; +}; + +static struct list Handles = LIST_INIT(Handles); + +struct HandleInstance +{ + struct list entry; + void *object; + HANDLE handle; + ULONG refs; +}; + #ifdef __i386__ #define DEFINE_FASTCALL1_ENTRYPOINT( name ) \ __ASM_GLOBAL_FUNC( name, \ @@ -80,12 +129,128 @@ struct IrpInstance "jmp " __ASM_NAME("__regs_") #name ) #endif +NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp ); + static inline LPCSTR debugstr_us( const UNICODE_STRING *us ) { if (!us) return ""; return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) ); } +static BOOL start_service( 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; + } + + ret = StartServiceW( service, 0, NULL ); + if (!ret && ERROR_SERVICE_ALREADY_RUNNING == GetLastError()) + ret = TRUE; + + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + + return ret; +} + +/* get name of driver service for device with given id */ +static BOOL get_service( WCHAR *device_id, WCHAR **service_name ) +{ + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + HDEVINFO set; + WCHAR *ptr, *enum_name, *id = NULL; + DWORD size, i = 0; + BOOL ret; + + *service_name = NULL; + ptr = strchrW( device_id, '\\' ); + if (!ptr) return FALSE; + size = ptr - device_id + 1; + enum_name = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ); + if (!enum_name) return FALSE; + lstrcpynW( enum_name, device_id, size ); + + set = SetupDiGetClassDevsW( NULL, enum_name, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) goto end; + while (SetupDiEnumDeviceInfo( set, i++, &devInfo )) + { + SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID, + NULL, NULL, 0, &size ); + if (id) RtlFreeHeap( GetProcessHeap(), 0, id ); + id = RtlAllocateHeap( GetProcessHeap(), 0, size ); + if (!id) break; + ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID, + NULL, (BYTE *)id, size, NULL ); + if (!ret) break; + if (strcmpiW( device_id, id )) continue; + SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE, + NULL, NULL, 0, &size ); + *service_name = RtlAllocateHeap( GetProcessHeap(), 0, size ); + if (!*service_name) break; + ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE, + NULL, (BYTE *)*service_name, size, NULL ); + if (!ret) + { + RtlFreeHeap( GetProcessHeap(), 0, *service_name ); + *service_name = NULL; + break; + } + } + SetupDiDestroyDeviceInfoList( set ); +end: + if (id) RtlFreeHeap( GetProcessHeap(), 0, id ); + if (enum_name) RtlFreeHeap( GetProcessHeap(), 0, enum_name ); + return (*service_name != NULL); +} + +static NTSTATUS get_device_id( DEVICE_OBJECT *pdo, BUS_QUERY_ID_TYPE id_type, + WCHAR **id ) +{ + NTSTATUS status; + IO_STACK_LOCATION *irpsp; + IRP *irp; + + *id = NULL; + irp = IoAllocateIrp( pdo->StackSize, FALSE ); + if (irp == NULL) return STATUS_NO_MEMORY; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + irpsp->MajorFunction = IRP_MJ_PNP; + irpsp->MinorFunction = IRP_MN_QUERY_ID; + irpsp->Parameters.QueryId.IdType = id_type; + status = __regs_IofCallDriver( 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; +} + static HANDLE get_device_manager(void) { static HANDLE device_manager; @@ -114,6 +279,41 @@ static HANDLE get_device_manager(void) return ret; } +static NTSTATUS get_autogenerated_device_name( UNICODE_STRING *name ) +{ + static const WCHAR autogen_nameW[] = {'\\','D','e','v','i','c','e', + '\\','%','0','8','x',0}; + + NTSTATUS status; + WCHAR *nameW; + HANDLE handle; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + unsigned int k = 1; + + if (!(nameW = RtlAllocateHeap( GetProcessHeap(), 0, 17 * sizeof(WCHAR) ))) + return STATUS_NO_MEMORY; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = name; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + for (;;) + { + 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; + } + return STATUS_SUCCESS; +} + /* exception handler for emulation of privileged instructions */ static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs ) { @@ -135,61 +335,69 @@ static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs ) return EXCEPTION_CONTINUE_SEARCH; } +/* get id of the process whose request is being handled */ +static DWORD get_pid(void) +{ + DWORD ret = 0, thread_id = GetCurrentThreadId(); + struct DriverInstance *drv; + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry ) + { + if (drv->driver_thread_id == thread_id) + { + ret = drv->process_id; + break; + } + } + LeaveCriticalSection( &cs ); + return ret; +} + +/* save id of the process whose request is being handled */ +static void save_pid( DWORD pid ) +{ + DWORD thread_id = GetCurrentThreadId(); + struct DriverInstance *drv; + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( drv, &Drivers, struct DriverInstance, entry ) + { + if (drv->driver_thread_id == thread_id) + { + drv->process_id = pid; + break; + } + } + 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 ) { - IRP irp; - MDL mdl; - IO_STACK_LOCATION irpsp; - PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; + PIRP irp; + PIO_STACK_LOCATION irpsp; 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 ); - /* so we can spot things that we should initialize */ - memset( &irp, 0x55, sizeof(irp) ); - memset( &irpsp, 0x66, sizeof(irpsp) ); - memset( &mdl, 0x77, sizeof(mdl) ); - - irp.RequestorMode = UserMode; - irp.AssociatedIrp.SystemBuffer = in_buff; - irp.UserBuffer = out_buff; - irp.MdlAddress = &mdl; - irp.Tail.Overlay.s.u.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; + irp = IoBuildDeviceIoControlRequest( code, device, in_buff, in_size, + out_buff, *out_size, FALSE, NULL, &iosb ); + if (irp == NULL) + return STATUS_NO_MEMORY; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + irp->RequestorMode = UserMode; + irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + irpsp->DeviceObject = device; + device->CurrentIrp = irp; KeQueryTickCount( &count ); /* update the global KeTickCount */ - - 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 ); - - *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0; - return irp.IoStatus.u.Status; + status = __regs_IofCallDriver( device, irp ); + *out_size = (status >= 0) ? iosb.Information : 0; + return status; } @@ -206,6 +414,7 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) DEVICE_OBJECT *device = NULL; ULONG in_size = 4096, out_size = 0; HANDLE handles[2]; + DWORD pid = 0; if (!(in_buff = HeapAlloc( GetProcessHeap(), 0, in_size ))) { @@ -229,6 +438,7 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) { code = reply->code; ioctl = reply->next; + pid = reply->pid; device = wine_server_get_ptr( reply->user_ptr ); in_size = reply->in_size; out_size = reply->out_size; @@ -242,12 +452,16 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) } SERVER_END_REQ; + save_pid( 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: @@ -269,6 +483,164 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) /*********************************************************************** + * __wine_add_driver_object (Not a Windows API) + */ +BOOL CDECL __wine_add_driver_object( DRIVER_OBJECT *driver, const WCHAR *service ) +{ + struct DriverInstance *drv; + + drv = HeapAlloc( GetProcessHeap(), 0, sizeof(*drv) ); + if (drv == NULL) return FALSE; + drv->driver = driver; + drv->service = service; + drv->driver_thread_id = GetCurrentThreadId(); + drv->process_id = 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 (!strcmpW( 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( DRIVER_OBJECT *driver ) +{ + DEVICE_OBJECT *device = driver->DeviceObject; + 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 = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + 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 = __regs_IofCallDriver( 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, @@ -276,11 +648,31 @@ NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject, ULONG DriverObjectExtensionSize, PVOID *DriverObjectExtension ) { - FIXME( "stub: %p, %p, %u, %p\n", DriverObject, ClientIdentificationAddress, + struct DriverObjExtension *ext; + + TRACE( "%p, %p, %u, %p\n", DriverObject, ClientIdentificationAddress, DriverObjectExtensionSize, DriverObjectExtension ); - return STATUS_NOT_IMPLEMENTED; -} + *DriverObjectExtension = NULL; + if (IoGetDriverObjectExtension( DriverObject, ClientIdentificationAddress )) + return STATUS_OBJECT_NAME_COLLISION; + ext = ExAllocatePool( NonPagedPool, sizeof(*ext) ); + if (ext == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + ext->ptr = ExAllocatePool( NonPagedPool, DriverObjectExtensionSize ); + if (ext->ptr == NULL) + { + ExFreePool( ext ); + return STATUS_INSUFFICIENT_RESOURCES; + } + ext->driver = DriverObject; + ext->id_addr = ClientIdentificationAddress; + EnterCriticalSection( &cs ); + list_add_tail( &DriverObjExtensions, &ext->entry ); + LeaveCriticalSection( &cs ); + *DriverObjectExtension = ext->ptr; + return STATUS_SUCCESS; +} /*********************************************************************** * IoGetDriverObjectExtension (NTOSKRNL.EXE.@) @@ -288,10 +680,24 @@ NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject, PVOID WINAPI IoGetDriverObjectExtension( PDRIVER_OBJECT DriverObject, PVOID ClientIdentificationAddress ) { - FIXME( "stub: %p, %p\n", DriverObject, ClientIdentificationAddress ); - return NULL; -} + struct DriverObjExtension *ext; + void *ext_ptr = NULL; + TRACE( "%p, %p\n", DriverObject, ClientIdentificationAddress ); + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( ext, &DriverObjExtensions, struct DriverObjExtension, entry ) + { + if (DriverObject == ext->driver && + ClientIdentificationAddress == ext->id_addr) + { + ext_ptr = ext->ptr; + break; + } + } + LeaveCriticalSection( &cs ); + return ext_ptr; +} /*********************************************************************** * IoInitializeIrp (NTOSKRNL.EXE.@) @@ -350,12 +756,73 @@ void WINAPI IoFreeIrp( IRP *irp ) */ PMDL WINAPI IoAllocateMdl( PVOID VirtualAddress, ULONG Length, BOOLEAN SecondaryBuffer, BOOLEAN ChargeQuota, PIRP Irp ) { - FIXME( "stub: %p, %u, %i, %i, %p\n", VirtualAddress, Length, SecondaryBuffer, ChargeQuota, Irp ); + HANDLE process; + PMDL mdl; + PVOID ptr; + SIZE_T bytes_read; + DWORD process_id = get_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_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 ) @@ -394,6 +861,8 @@ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode, PIRP irp; PIO_STACK_LOCATION irpsp; struct IrpInstance *instance; + CHAR *buf = NULL; + MDL *mdl = NULL; TRACE( "%x, %p, %p, %u, %p, %u, %u, %p, %p\n", IoControlCode, DeviceObject, InputBuffer, InputBufferLength, @@ -407,23 +876,59 @@ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode, if (irp == NULL) return NULL; - instance = HeapAlloc( GetProcessHeap(), 0, sizeof(struct IrpInstance) ); - if (instance == NULL) - { - IoFreeIrp( irp ); - return NULL; - } - instance->irp = irp; - list_add_tail( &Irps, &instance->entry ); - irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; irpsp->MajorFunction = InternalDeviceIoControl ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; irpsp->Parameters.DeviceIoControl.IoControlCode = IoControlCode; + irpsp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; + irpsp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; irp->UserIosb = IoStatusBlock; irp->UserEvent = Event; + switch (IoControlCode & 3) + { + case METHOD_BUFFERED: + buf = ExAllocatePool( NonPagedPool, max( OutputBufferLength, InputBufferLength ) ); + if (buf == NULL) + goto err; + memcpy( buf, InputBuffer, InputBufferLength ); + irp->AssociatedIrp.SystemBuffer = buf; + irp->UserBuffer = OutputBuffer; + break; + case METHOD_NEITHER: + irpsp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer; + irp->UserBuffer = OutputBuffer; + break; + default: + irp->AssociatedIrp.SystemBuffer = InputBuffer; + mdl = ExAllocatePool( NonPagedPool, sizeof(*mdl) ); + if (mdl == NULL) + goto err; + mdl->Next = NULL; + mdl->Size = 0; + mdl->StartVa = OutputBuffer; + mdl->MappedSystemVa = OutputBuffer; + mdl->ByteCount = OutputBufferLength; + mdl->ByteOffset = 0; + irp->MdlAddress = mdl; + } + + instance = HeapAlloc( GetProcessHeap(), 0, sizeof(struct IrpInstance) ); + if (instance == NULL) + goto err; + instance->irp = irp; + EnterCriticalSection( &cs ); + list_add_tail( &Irps, &instance->entry ); + LeaveCriticalSection( &cs ); + return irp; +err: + if (buf) + ExFreePool( buf ); + if (mdl) + ExFreePool( mdl ); + IoFreeIrp( irp ); + return NULL; } @@ -486,6 +991,7 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, DEVICE_OBJECT *device; HANDLE handle = 0; HANDLE manager = get_device_manager(); + UNICODE_STRING generated_name; TRACE( "(%p, %u, %s, %u, %x, %u, %p)\n", driver, ext_size, debugstr_us(name), type, characteristics, exclusive, ret_device ); @@ -493,6 +999,17 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, if (!(device = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*device) + ext_size ))) return STATUS_NO_MEMORY; + if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME) + { + status = get_autogenerated_device_name( &generated_name ); + if (status != STATUS_SUCCESS) + { + HeapFree( GetProcessHeap(), 0, device ); + return status; + } + name = &generated_name; + } + SERVER_START_REQ( create_device ) { req->access = 0; @@ -507,7 +1024,11 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, if (status == STATUS_SUCCESS) { + device->Type = IO_TYPE_DEVICE; + device->Size = sizeof(*device) + ext_size; device->DriverObject = driver; + device->Flags = DO_DEVICE_INITIALIZING; + if (name) device->Flags |= DO_DEVICE_HAS_NAME; device->DeviceExtension = device + 1; device->DeviceType = type; device->StackSize = 1; @@ -520,6 +1041,8 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size, } else HeapFree( GetProcessHeap(), 0, device ); + if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME) + RtlFreeUnicodeString( &generated_name ); return status; } @@ -573,6 +1096,192 @@ NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *targ /*********************************************************************** + * IoInvalidateDeviceRelations (NTOSKRNL.EXE.@) + */ +void WINAPI IoInvalidateDeviceRelations( PDEVICE_OBJECT DeviceObject, + DEVICE_RELATION_TYPE Type ) +{ + TRACE( "%p, %u\n", DeviceObject, Type ); + + while (DeviceObject->AttachedDevice) + DeviceObject = DeviceObject->AttachedDevice; + if (Type == BusRelations) + { + DEVICE_RELATIONS *rel; + IO_STACK_LOCATION *irpsp; + IRP *irp; + NTSTATUS status; + + irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); + if (irp == NULL) return; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + irpsp->MajorFunction = IRP_MJ_PNP; + irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; + irpsp->Parameters.QueryDeviceRelations.Type = BusRelations; + status = __regs_IofCallDriver( 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 = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + irpsp->MajorFunction = IRP_MJ_PNP; + irpsp->MinorFunction = IRP_MN_QUERY_ID; + irpsp->Parameters.QueryId.IdType = BusQueryDeviceID; + status = __regs_IofCallDriver( rel->Objects[k], irp ); + if (status == STATUS_SUCCESS) + { + WCHAR *service; + + if (get_service( (WCHAR *)irp->IoStatus.Information, &service ) + && 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) + __wine_start_device( driver ); + } + 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 ); +} + + +/*********************************************************************** + * IoIsWdmVersionAvailable (NTOSKRNL.EXE.@) + */ +BOOLEAN WINAPI IoIsWdmVersionAvailable( UCHAR MajorVersion, UCHAR MinorVersion ) +{ + FIXME( "stub: %u %u\n", MajorVersion, MinorVersion ); + return FALSE; +} + + +/*********************************************************************** + * IoRegisterDeviceInterface (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT PhysicalDeviceObject, + CONST GUID *InterfaceClassGuid, + PUNICODE_STRING ReferenceString, + PUNICODE_STRING SymbolicLinkName ) +{ + WCHAR *hardware_id = NULL, *instance_id = NULL, *id = NULL; + WCHAR *ptr, *target, *enumerator = NULL; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = NULL; + HDEVINFO set; + SP_DEVINFO_DATA devInfo; + SP_DEVICE_INTERFACE_DATA interfaceData; + DWORD i = 0; + NTSTATUS status; + struct InterfaceInstance *interf; + DWORD size; + + TRACE( "%p %s %s %p\n", PhysicalDeviceObject, + debugstr_guid(InterfaceClassGuid), debugstr_us(ReferenceString), + SymbolicLinkName ); + + status = get_device_id( PhysicalDeviceObject, BusQueryInstanceID, &instance_id ); + if (status != STATUS_SUCCESS) goto end; + status = get_device_id( PhysicalDeviceObject, BusQueryDeviceID, &hardware_id ); + if (status != STATUS_SUCCESS) goto end; + ptr = strchrW( hardware_id, '\\' ) + 1; + size = (char *)ptr - (char *)hardware_id; + enumerator = RtlAllocateHeap( GetProcessHeap(), 0, size ); + id = RtlAllocateHeap( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN ); + if (enumerator == NULL || id == NULL) + { + status = STATUS_NO_MEMORY; + goto end; + } + lstrcpynW( enumerator, hardware_id, size / sizeof(WCHAR) ); + + status = STATUS_UNSUCCESSFUL; + set = SetupDiGetClassDevsW( NULL, enumerator, NULL, DIGCF_ALLCLASSES ); + if (INVALID_HANDLE_VALUE == set) goto end; + devInfo.cbSize = sizeof(devInfo); + while (SetupDiEnumDeviceInfo( set, i++, &devInfo )) + if (SetupDiGetDeviceInstanceIdW( set, &devInfo, id, MAX_DEVICE_ID_LEN, NULL ) + && compare_ids( hardware_id, instance_id, id )) + { + interfaceData.cbSize = sizeof(interfaceData); + if (SetupDiCreateDeviceInterfaceW( set, &devInfo, + InterfaceClassGuid, NULL, 0, &interfaceData )) + { + SetupDiGetDeviceInterfaceDetailW( set, &interfaceData, NULL, 0, + &size, NULL ); + detail = RtlAllocateHeap( GetProcessHeap(), 0, size ); + if (detail == NULL) break; + detail->cbSize = sizeof(*detail); + if (!SetupDiGetDeviceInterfaceDetailW( set, &interfaceData, + detail, size, NULL, NULL )) + break; + interf = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*interf) ); + if (interf == NULL) break; + interf->link = RtlAllocateHeap( GetProcessHeap(), 0, + (strlenW(detail->DevicePath) + 1) * sizeof(WCHAR) ); + if (interf->link == NULL) + { + RtlFreeHeap( GetProcessHeap(), 0, interf ); + break; + } + strcpyW( interf->link, detail->DevicePath ); + interf->link[1] = '?'; + 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 ); + EnterCriticalSection( &cs ); + list_add_tail( &Interfaces, &interf->entry ); + LeaveCriticalSection( &cs ); + } + else + { + RtlFreeHeap( GetProcessHeap(), 0, target ); + RtlFreeHeap( GetProcessHeap(), 0, interf->link ); + RtlFreeHeap( GetProcessHeap(), 0, interf ); + } + } + break; + } + SetupDiDestroyDeviceInfoList( set ); + + if (STATUS_SUCCESS == status) + RtlCreateUnicodeString( SymbolicLinkName, interf->link ); +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 ) @@ -603,6 +1312,40 @@ NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name ) /*********************************************************************** + * 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 = STATUS_OBJECT_NAME_NOT_FOUND; + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( interf, &Interfaces, struct InterfaceInstance, entry ) + { + if (!strncmpW( SymbolicLinkName->Buffer, interf->link, + SymbolicLinkName->Length )) + { + status = IoCreateSymbolicLink( SymbolicLinkName, &interf->target ); + break; + } + } + LeaveCriticalSection( &cs ); + return status; + } + else + { + FIXME( "Disabling interface is not supported\n" ); + return STATUS_NOT_IMPLEMENTED; + } +} + + +/*********************************************************************** * IoGetDeviceObjectPointer (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK access, PFILE_OBJECT *file, PDEVICE_OBJECT *device ) @@ -613,6 +1356,55 @@ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK acc /*********************************************************************** + * IoGetDeviceProperty (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoGetDeviceProperty( PDEVICE_OBJECT DeviceObject, + DEVICE_REGISTRY_PROPERTY DeviceProperty, + ULONG BufferLength, PVOID PropertyBuffer, + PULONG ResultLength ) +{ + NTSTATUS status; + + TRACE( "%p %u %u %p %p\n", DeviceObject, DeviceProperty, BufferLength, + PropertyBuffer, ResultLength ); + + switch (DeviceProperty) + { + case DevicePropertyPhysicalDeviceObjectName: + { + static const WCHAR device[] = {'\\','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( DeviceObject->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; + + *ResultLength = len + sizeof(device); + if (BufferLength >= *ResultLength) + { + strcpyW( PropertyBuffer, device ); + device_name[len / sizeof(WCHAR)] = 0; + strcatW( PropertyBuffer, device_name ); + } + break; + } + default: + FIXME( "device property %u is not supported\n", DeviceProperty ); + status = STATUS_NOT_IMPLEMENTED; + } + + return status; +} + + +/*********************************************************************** * IofCallDriver (NTOSKRNL.EXE.@) */ #ifdef DEFINE_FASTCALL2_ENTRYPOINT @@ -631,11 +1423,28 @@ NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) --irp->CurrentLocation; irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation; dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction]; + + 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; } +/*********************************************************************** + * IoGetAttachedDeviceReference (NTOSKRNL.EXE.@) + */ +PDEVICE_OBJECT WINAPI IoGetAttachedDeviceReference( PDEVICE_OBJECT obj ) +{ + FIXME( "stub: %p\n", obj ); + return obj; +} /*********************************************************************** * IoGetRelatedDeviceObject (NTOSKRNL.EXE.@) @@ -679,20 +1488,16 @@ NTSTATUS WINAPI IoRegisterShutdownNotification( PDEVICE_OBJECT obj ) /*********************************************************************** - * IofCompleteRequest (NTOSKRNL.EXE.@) + * wine_complete_request (Not a Windows API) */ -#ifdef DEFINE_FASTCALL2_ENTRYPOINT -DEFINE_FASTCALL2_ENTRYPOINT( IofCompleteRequest ) -void WINAPI __regs_IofCompleteRequest( IRP *irp, UCHAR priority_boost ) -#else -void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost ) -#endif +void CDECL wine_complete_request( IRP *irp, UCHAR priority_boost ) { IO_STACK_LOCATION *irpsp; PIO_COMPLETION_ROUTINE routine; IO_STATUS_BLOCK *iosb; struct IrpInstance *instance; NTSTATUS status, stat; + KEVENT *event; int call_flag = 0; TRACE( "%p %u\n", irp, priority_boost ); @@ -724,21 +1529,52 @@ void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost ) 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; + list_remove( &instance->entry ); HeapFree( GetProcessHeap(), 0, instance ); + if (mdl) + { + ExFreePool( mdl ); + } + else if (buf) + { + memcpy( irp->UserBuffer, buf, irp->IoStatus.Information ); + ExFreePool( buf ); + } IoFreeIrp( irp ); break; } } + LeaveCriticalSection( &cs ); + if (event) + KeSetEvent( event, 0, FALSE ); +} + + +/*********************************************************************** + * IofCompleteRequest (NTOSKRNL.EXE.@) + */ +#ifdef DEFINE_FASTCALL2_ENTRYPOINT +DEFINE_FASTCALL2_ENTRYPOINT( IofCompleteRequest ) +void WINAPI __regs_IofCompleteRequest( IRP *irp, UCHAR priority_boost ) +#else +void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost ) +#endif +{ + return wine_complete_request( irp, priority_boost ); } @@ -871,11 +1707,132 @@ void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag ) /*********************************************************************** + * KeGetCurrentThread (NTOSKRNL.EXE.@) + */ +PKTHREAD WINAPI KeGetCurrentThread(void) +{ + FIXME( "stub\n" ); + 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 ) +void WINAPI KeInitializeEvent( PRKEVENT Event, EVENT_TYPE Type, + BOOLEAN State ) +{ + TRACE( "%p %u %u\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 ); +} + + +/*********************************************************************** + * KeResetEvent (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeResetEvent( PRKEVENT Event ) +{ + TRACE( "%p\n", Event ); + return InterlockedExchange( &Event->Header.SignalState, 0 ); +} + + +/*********************************************************************** + * KeSetEvent (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeSetEvent( PRKEVENT Event, KPRIORITY Increment, + BOOLEAN Wait ) +{ + 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; +} + + +/*********************************************************************** + * KeInitializeMutex (NTOSKRNL.EXE.@) + */ +void WINAPI KeInitializeMutex( PRKMUTEX Mutex, ULONG 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; +} + + +/*********************************************************************** + * KeReleaseMutex (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeReleaseMutex( PRKMUTEX Mutex, BOOLEAN Wait ) +{ + FIXME("stub: %p %d\n", Mutex, Wait); + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * KeInitializeSemaphore (NTOSKRNL.EXE.@) + */ +void WINAPI KeInitializeSemaphore( PRKSEMAPHORE Semaphore, LONG Count, LONG Limit ) +{ + FIXME("stub: %p %d %d\n", Semaphore, Count, Limit); + RtlZeroMemory( Semaphore, sizeof(KSEMAPHORE) ); + Semaphore->Header.Type = 5; +} + + +/*********************************************************************** + * KeReleaseSemaphore (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeReleaseSemaphore( PRKSEMAPHORE Semaphore, KPRIORITY Increment, + LONG Adjustment, BOOLEAN Wait ) { - FIXME( "stub: %p %d %d\n", Event, Type, State ); + FIXME("stub: %p %d %d %d\n", Semaphore, Increment, Adjustment, Wait); + return 0; } @@ -889,11 +1846,24 @@ void WINAPI KeInitializeSpinLock( PKSPIN_LOCK SpinLock ) /*********************************************************************** + * PoSetPowerState (NTOSKRNL.EXE.@) + */ +UINT WINAPI PoSetPowerState( PDEVICE_OBJECT DeviceObject, + POWER_STATE_TYPE Type, POWER_STATE State ) +{ + FIXME("stub: %p %u %u\n", DeviceObject, Type, State.DeviceState); + return State.DeviceState; +} + + +/*********************************************************************** * KeInitializeTimerEx (NTOSKRNL.EXE.@) */ 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; } @@ -971,6 +1941,104 @@ ULONG WINAPI KeQueryTimeIncrement(void) /*********************************************************************** + * KeSetPriorityThread (NTOSKRNL.EXE.@) + */ +KPRIORITY WINAPI KeSetPriorityThread( PKTHREAD Thread, KPRIORITY Priority ) +{ + FIXME( "stub: %p %d\n", Thread, Priority ); + return 0; +} + + +/*********************************************************************** + * KeWaitForSingleObject (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI KeWaitForSingleObject( PVOID Object, KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, BOOLEAN Alertable, + PLARGE_INTEGER Timeout ) +{ + DISPATCHER_HEADER *header = Object; + NTSTATUS status = STATUS_SUCCESS; + + TRACE("%p %u %d %d %p\n", Object, WaitReason, WaitMode, Alertable, Timeout); + + switch (header->Type) + { + case NotificationEvent: + case SynchronizationEvent: + { + struct HandleInstance *inst; + HANDLE event_handle = NULL; + + if (InterlockedCompareExchange( &header->SignalState, 0, header->Type )) + { + status = STATUS_SUCCESS; + break; + } + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry ) + { + if (inst->object == Object) + { + event_handle = inst->handle; + ++inst->refs; + break; + } + } + while (event_handle == NULL) + { + OBJECT_ATTRIBUTES attr; + + RtlZeroMemory( &attr, sizeof(attr) ); + attr.Length = sizeof(attr); + status = NtCreateEvent( &event_handle, EVENT_ALL_ACCESS, &attr, + !header->Type, FALSE ); + if (status != STATUS_SUCCESS) + break; + inst = HeapAlloc( GetProcessHeap(), 0, sizeof(*inst) ); + if (inst == NULL) + { + NtClose( event_handle ); + status = STATUS_NO_MEMORY; + break; + } + inst->object = Object; + inst->handle = event_handle; + inst->refs = 1; + list_add_head( &Handles, &inst->entry ); + } + LeaveCriticalSection( &cs ); + if (status != STATUS_SUCCESS) + break; + + status = NtWaitForSingleObject( event_handle, Alertable, Timeout ); + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry ) + { + if (inst->object == Object) + { + if (!--inst->refs) + { + list_remove( &inst->entry ); + NtClose( inst->handle ); + HeapFree( GetProcessHeap(), 0, inst ); + } + break; + } + } + LeaveCriticalSection( &cs ); + break; + } + default: + WARN( "synchronization object %u is not supported\n", header->Type ); + } + return status; +} + + +/*********************************************************************** * MmAllocateNonCachedMemory (NTOSKRNL.EXE.@) */ PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size ) @@ -1008,6 +2076,16 @@ BOOLEAN WINAPI MmIsAddressValid(PVOID VirtualAddress) return !IsBadWritePtr(VirtualAddress, 1); } + /*********************************************************************** + * MmMapLockedPages (NTOSKRNL.EXE.@) + */ +PVOID WINAPI MmMapLockedPages(PMDL MemoryDescriptorList, + KPROCESSOR_MODE AccessMode) +{ + TRACE("%p %d\n", MemoryDescriptorList, AccessMode); + return MemoryDescriptorList->MappedSystemVa; +} + /*********************************************************************** * MmPageEntireDriver (NTOSKRNL.EXE.@) */ @@ -1018,6 +2096,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) @@ -1025,6 +2113,14 @@ void WINAPI MmResetDriverPaging(PVOID AddrInSection) TRACE("%p\n", AddrInSection); } +/*********************************************************************** + * MmUnmapLockedPages (NTOSKRNL.EXE.@) + */ +void WINAPI MmUnmapLockedPages(PVOID BaseAddress, PMDL MemoryDescriptorList) +{ + TRACE("%p %p\n", BaseAddress, MemoryDescriptorList); +} + /*********************************************************************** * ObReferenceObjectByHandle (NTOSKRNL.EXE.@) @@ -1040,6 +2136,18 @@ NTSTATUS WINAPI ObReferenceObjectByHandle( HANDLE obj, ACCESS_MASK access, /*********************************************************************** + * 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; +} + + +/*********************************************************************** * ObfDereferenceObject (NTOSKRNL.EXE.@) */ #ifdef DEFINE_FASTCALL1_ENTRYPOINT @@ -1054,6 +2162,14 @@ void WINAPI ObfDereferenceObject( VOID *obj ) /*********************************************************************** + * MmUnlockPages (NTOSKRNL.EXE.@) + */ +void WINAPI MmUnlockPages(PMDL MemoryDescriptorList) +{ + FIXME("stub: %p\n", MemoryDescriptorList); +} + +/*********************************************************************** * PsCreateSystemThread (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess, @@ -1179,6 +2295,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) { @@ -1186,9 +2304,26 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) DisableThreadLibraryCalls( inst ); handler = RtlAddVectoredExceptionHandler( TRUE, vectored_handler ); KeQueryTickCount( &count ); /* initialize the global KeTickCount */ + InitializeCriticalSection( &cs ); break; case DLL_PROCESS_DETACH: + DeleteCriticalSection( &cs ); RtlRemoveVectoredExceptionHandler( handler ); + LIST_FOR_EACH_ENTRY_SAFE( ext, ext2, &DriverObjExtensions, + struct DriverObjExtension, entry ) + { + list_remove( &ext->entry ); + ExFreePool( ext->ptr ); + ExFreePool( ext ); + } + LIST_FOR_EACH_ENTRY_SAFE( intf, intf2, &Interfaces, + struct InterfaceInstance, entry ) + { + list_remove( &intf->entry ); + RtlFreeUnicodeString( &intf->target ); + RtlFreeHeap( GetProcessHeap(), 0, intf->link ); + RtlFreeHeap( GetProcessHeap(), 0, intf ); + } break; } return TRUE; diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 849dd51..f7512b9 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 @@ -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() @@ -383,7 +383,7 @@ @ stub IoGetDeviceInterfaceAlias @ stub IoGetDeviceInterfaces @ stdcall IoGetDeviceObjectPointer(ptr long ptr ptr) -@ stub IoGetDeviceProperty +@ stdcall IoGetDeviceProperty(ptr long long ptr ptr) @ stub IoGetDeviceToVerify @ stub IoGetDiskDeviceObject @ stub IoGetDmaAdapter @@ -400,13 +400,13 @@ @ stdcall IoInitializeIrp(ptr long long) @ stub IoInitializeRemoveLockEx @ stub IoInitializeTimer -@ stub IoInvalidateDeviceRelations +@ stdcall IoInvalidateDeviceRelations(ptr long) @ stub IoInvalidateDeviceState @ stub IoIsFileOriginRemote @ stub IoIsOperationSynchronous @ stub IoIsSystemThread @ stub IoIsValidNameGraftingBuffer -@ stub IoIsWdmVersionAvailable +@ stdcall IoIsWdmVersionAvailable(long long) @ stub IoMakeAssociatedIrp @ stub IoOpenDeviceInterfaceRegistryKey @ stub IoOpenDeviceRegistryKey @@ -425,14 +425,14 @@ @ stub IoReadPartitionTableEx @ stub IoReadTransferCount @ stub IoRegisterBootDriverReinitialization -@ stub IoRegisterDeviceInterface +@ stdcall IoRegisterDeviceInterface(ptr ptr ptr ptr) @ stdcall IoRegisterDriverReinitialization(ptr ptr ptr) @ stub IoRegisterFileSystem @ stub IoRegisterFsRegistrationChange @ stub IoRegisterLastChanceShutdownNotification @ stub IoRegisterPlugPlayNotification +@ stdcall IoReleaseCancelSpinLock(long) @ stdcall IoRegisterShutdownNotification(ptr) -@ stub IoReleaseCancelSpinLock @ 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 @@ -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 @@ -529,7 +529,7 @@ @ stub KeFindConfigurationNextEntry @ stub KeFlushEntireTb @ stub KeFlushQueuedDpcs -@ stub KeGetCurrentThread +@ stdcall KeGetCurrentThread() @ stub KeGetPreviousMode @ stub KeGetRecommendedSharedDataAlignment @ stub KeI386AbiosCall @@ -549,9 +549,9 @@ @ stdcall KeInitializeEvent(ptr long long) @ stub KeInitializeInterrupt @ stub KeInitializeMutant -@ stub KeInitializeMutex +@ stdcall KeInitializeMutex(ptr long) @ stub KeInitializeQueue -@ stub KeInitializeSemaphore +@ stdcall KeInitializeSemaphore(ptr long long) @ stdcall KeInitializeSpinLock(ptr) @ stdcall KeInitializeTimer(ptr) @ stdcall KeInitializeTimerEx(ptr long) @@ -587,8 +587,8 @@ @ stub KeRegisterBugCheckReasonCallback @ stub KeReleaseInterruptSpinLock @ stub KeReleaseMutant -@ stub KeReleaseMutex -@ stub KeReleaseSemaphore +@ stdcall KeReleaseMutex(ptr long) +@ stdcall KeReleaseSemaphore(ptr long long long) @ stub KeReleaseSpinLockFromDpcLevel @ stub KeRemoveByKeyDeviceQueue @ stub KeRemoveByKeyDeviceQueueIfBusy @@ -597,7 +597,7 @@ @ stub KeRemoveQueue @ stub KeRemoveQueueDpc @ stub KeRemoveSystemServiceTable -@ stub KeResetEvent +@ stdcall KeResetEvent(ptr) @ stub KeRestoreFloatingPointState @ stub KeRevertToUserAffinityThread @ stub KeRundownQueue @@ -607,12 +607,12 @@ @ stub KeSetAffinityThread @ stub KeSetBasePriorityThread @ stub KeSetDmaIoCoherency -@ stub KeSetEvent +@ stdcall KeSetEvent(ptr long long) @ stub KeSetEventBoostPriority @ stub KeSetIdealProcessorThread @ stub KeSetImportanceDpc @ stub KeSetKernelStackSwapEnable -@ stub KeSetPriorityThread +@ stdcall KeSetPriorityThread(ptr long) @ stub KeSetProfileIrql @ stub KeSetSystemAffinityThread @ stub KeSetTargetProcessorDpc @@ -629,7 +629,7 @@ @ stub KeUserModeCallback @ stub KeWaitForMultipleObjects @ stub KeWaitForMutexObject -@ stub KeWaitForSingleObject +@ stdcall KeWaitForSingleObject(ptr long long long ptr) @ stub KiBugCheckData @ stub KiCoprocessorError @ stub KiDeliverApc @@ -689,7 +689,7 @@ @ stub MmLockPagableImageSection @ stub MmLockPagableSectionByHandle @ stub MmMapIoSpace -@ 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) @ stub MmUnmapIoSpace -@ stub MmUnmapLockedPages +@ stdcall MmUnmapLockedPages(ptr ptr) @ stub MmUnmapReservedMapping @ stub MmUnmapVideoDisplay @ stub MmUnmapViewInSessionSpace @@ -811,7 +811,7 @@ @ stub ObQueryObjectAuditingByHandle @ stdcall ObReferenceObjectByHandle(long long ptr long ptr ptr) @ stub ObReferenceObjectByName -@ stub ObReferenceObjectByPointer +@ stdcall ObReferenceObjectByPointer(ptr long ptr long) @ stub ObReferenceSecurityDescriptor @ stub ObReleaseObjectSecurity @ stub ObSetHandleAttributes @@ -830,7 +830,7 @@ @ stub PoRequestPowerIrp @ stub PoRequestShutdownEvent @ stub PoSetHiberRange -@ stub PoSetPowerState +@ stdcall PoSetPowerState(ptr long long) @ stub PoSetSystemState @ stub PoShutdownBugCheck @ stub PoStartNextPowerIrp @@ -1489,3 +1489,9 @@ # or 'wine_' (for user-visible functions) to avoid namespace conflicts. @ cdecl wine_ntoskrnl_main_loop(long) +@ cdecl wine_complete_request(ptr 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) diff --git a/dlls/usbd.sys/Makefile.in b/dlls/usbd.sys/Makefile.in new file mode 100644 index 0000000..f745ffb --- /dev/null +++ b/dlls/usbd.sys/Makefile.in @@ -0,0 +1,15 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = usbd.sys +IMPORTLIB = usbd.sys +IMPORTS = kernel32 ntoskrnl.exe +EXTRADLLFLAGS = -Wb,--subsystem,native + +C_SRCS = \ + usbd.c + +@MAKE_DLL_RULES@ + +@DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/dlls/usbd.sys/usbd.c b/dlls/usbd.sys/usbd.c new file mode 100644 index 0000000..c7c8fab --- /dev/null +++ b/dlls/usbd.sys/usbd.c @@ -0,0 +1,145 @@ +/* + * 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 + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "ddk/wdm.h" +#include "ddk/usb.h" +#include "ddk/usbdlib.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(usbd); + +PURB WINAPI USBD_CreateConfigurationRequestEx( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + PUSBD_INTERFACE_LIST_ENTRY InterfaceList ) +{ + URB *urb; + UCHAR k, num_interfaces = 0; + SIZE_T size; + struct _URB_SELECT_CONFIGURATION *sel_conf; + USBD_INTERFACE_INFORMATION *if_info; + USB_INTERFACE_DESCRIPTOR *if_desc; + USBD_INTERFACE_LIST_ENTRY *entry; + + TRACE( "%p, %p\n", ConfigurationDescriptor, InterfaceList ); + + entry = InterfaceList; + size = sizeof(struct _URB_SELECT_CONFIGURATION); + while (entry->InterfaceDescriptor) + { + size += (entry->InterfaceDescriptor->bNumEndpoints - 1) * + sizeof(USBD_PIPE_INFORMATION); + ++num_interfaces; + ++entry; + } + size += (num_interfaces - 1) * sizeof(USBD_INTERFACE_INFORMATION); + + urb = ExAllocatePool( NonPagedPool, size ); + RtlZeroMemory( urb, size ); + + sel_conf = &urb->u.UrbSelectConfiguration; + sel_conf->Hdr.Length = size; + sel_conf->Hdr.Function = URB_FUNCTION_SELECT_CONFIGURATION; + sel_conf->ConfigurationDescriptor = ConfigurationDescriptor; + + entry = InterfaceList; + if_info = &sel_conf->Interface; + while (entry->InterfaceDescriptor) + { + if_desc = entry->InterfaceDescriptor; + entry->Interface = if_info; + if_info->InterfaceNumber = if_desc->bInterfaceNumber; + if_info->NumberOfPipes = if_desc->bNumEndpoints; + for (k = 0; k < if_info->NumberOfPipes; ++k) + if_info->Pipes[k].MaximumTransferSize = 4096; + if_info->Length = sizeof(USBD_INTERFACE_INFORMATION) + + (k - 1) * sizeof(USBD_PIPE_INFORMATION); + if_info = (USBD_INTERFACE_INFORMATION *)((char *)if_info + + if_info->Length); + ++entry; + } + + return urb; +} + +PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + PVOID StartPosition, LONG InterfaceNumber, + LONG AlternateSetting, LONG InterfaceClass, + LONG InterfaceSubClass, LONG InterfaceProtocol ) +{ + TRACE( "%p, %p, %d, %d, %d, %d, %d\n", ConfigurationDescriptor, + StartPosition, InterfaceNumber, AlternateSetting, + InterfaceClass, InterfaceSubClass, InterfaceProtocol ); + return (PUSB_INTERFACE_DESCRIPTOR)++ConfigurationDescriptor; +} + +PURB WINAPI USBD_CreateConfigurationRequest( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PUSHORT Siz ) +{ + USBD_INTERFACE_LIST_ENTRY *uile; + USB_INTERFACE_DESCRIPTOR *if_desc, *max; + ULONG uile_size, k = 0; + URB *urb; + + TRACE( "%p, %p\n", ConfigurationDescriptor, Siz ); + + uile_size = (ConfigurationDescriptor->bNumInterfaces + 1) * + sizeof(USBD_INTERFACE_LIST_ENTRY); + uile = ExAllocatePool( NonPagedPool, uile_size ); + if (NULL == uile) + return NULL; + RtlZeroMemory( uile, uile_size ); + + if_desc = (USB_INTERFACE_DESCRIPTOR *)(ConfigurationDescriptor + 1); + max = (USB_INTERFACE_DESCRIPTOR *)((char *)ConfigurationDescriptor + + ConfigurationDescriptor->wTotalLength); + while (if_desc < max && k < ConfigurationDescriptor->bNumInterfaces) + { + if (USB_INTERFACE_DESCRIPTOR_TYPE == if_desc->bDescriptorType) + uile[k++].InterfaceDescriptor = if_desc; + if_desc = (USB_INTERFACE_DESCRIPTOR *)((char *)if_desc + + if_desc->bLength); + } + + urb = USBD_CreateConfigurationRequestEx( ConfigurationDescriptor, uile ); + *Siz = (NULL == urb) ? 0 : urb->u.UrbSelectConfiguration.Hdr.Length; + + ExFreePool( uile ); + + return urb; +} + +void WINAPI USBD_GetUSBDIVersion( PUSBD_VERSION_INFORMATION VersionInformation ) +{ + TRACE( "%p\n", VersionInformation ); + VersionInformation->USBDI_Version = 0x300; + VersionInformation->Supported_USB_Version = 0x100; +} + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) +{ + return STATUS_SUCCESS; +} diff --git a/dlls/usbd.sys/usbd.sys.spec b/dlls/usbd.sys/usbd.sys.spec new file mode 100644 index 0000000..a18bbf8 --- /dev/null +++ b/dlls/usbd.sys/usbd.sys.spec @@ -0,0 +1,35 @@ +@ stdcall USBD_CreateConfigurationRequestEx(ptr ptr) +@ stdcall USBD_ParseConfigurationDescriptorEx(ptr ptr) +@ stub USBD_ParseDescriptors +@ stub DllInitialize +@ stub DllUnload +@ stub USBD_AllocateDeviceName +@ stub USBD_CalculateUsbBandwidth +@ stub USBD_CompleteRequest +@ stdcall USBD_CreateConfigurationRequest(ptr ptr) +@ stdcall _USBD_CreateConfigurationRequestEx@8(ptr ptr) USBD_CreateConfigurationRequestEx +@ stub USBD_CreateDevice +@ stub USBD_Debug_GetHeap +@ stub USBD_Debug_LogEntry +@ stub USBD_Debug_RetHeap +@ stub USBD_Dispatch +@ stub USBD_FreeDeviceMutex +@ stub USBD_FreeDeviceName +@ stub USBD_GetDeviceInformation +@ stub USBD_GetInterfaceLength +@ stub USBD_GetPdoRegistryParameter +@ stub USBD_GetSuspendPowerState +@ stdcall USBD_GetUSBDIVersion(ptr) +@ stub USBD_InitializeDevice +@ stub USBD_MakePdoName +@ stub USBD_ParseConfigurationDescriptor +@ stdcall _USBD_ParseConfigurationDescriptorEx@28(ptr ptr long long long long long) USBD_ParseConfigurationDescriptorEx +@ stub _USBD_ParseDescriptors@16 +@ stub USBD_QueryBusTime +@ stub USBD_RegisterHcDeviceCapabilities +@ stub USBD_RegisterHcFilter +@ stub USBD_RegisterHostController +@ stub USBD_RemoveDevice +@ stub USBD_RestoreDevice +@ stub USBD_SetSuspendPowerState +@ stub USBD_WaitDeviceMutex diff --git a/dlls/usbhub.sys/Makefile.in b/dlls/usbhub.sys/Makefile.in new file mode 100644 index 0000000..548fe4b --- /dev/null +++ b/dlls/usbhub.sys/Makefile.in @@ -0,0 +1,15 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = usbhub.sys +IMPORTS = ntoskrnl.exe kernel32 advapi32 setupapi ntdll +EXTRADLLFLAGS = -Wb,--subsystem,native +EXTRALIBS = @USBLIBS@ + +C_SRCS = \ + usbhub.c + +@MAKE_DLL_RULES@ + +@DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/dlls/usbhub.sys/usbhub.c b/dlls/usbhub.sys/usbhub.c new file mode 100644 index 0000000..1d9f52a --- /dev/null +++ b/dlls/usbhub.sys/usbhub.c @@ -0,0 +1,551 @@ +/* + * Copyright 2008 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 + +#ifdef HAVE_USB_H +#include +#endif + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "winreg.h" +#include "winsvc.h" +#include "winuser.h" +#include "setupapi.h" +#include "cfgmgr32.h" +#include "ddk/ntddk.h" +#include "ddk/usbdrivr.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(usbhub); + +extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev ); +extern void CDECL wine_complete_request( IRP *irp, UCHAR priority_boost ); +extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service ); +extern NTSTATUS CDECL __wine_start_device( DRIVER_OBJECT *driver ); + +static unsigned int last_pdo_num; + +static struct list Devices = LIST_INIT(Devices); + +struct DeviceInstance +{ + struct list entry; + USHORT vid; + USHORT pid; + char *instance_id; + WCHAR *service; + struct usb_device *dev; +}; + +struct PdoExtension +{ + struct DeviceInstance *instance; +}; + +#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H) +static void add_data( char **dst, int *dst_size, void *src, int src_size ) +{ + int copy; + + copy = (src_size >= *dst_size) ? *dst_size : src_size; + memcpy( *dst, src, copy ); + *dst += copy; + *dst_size -= copy; +} + +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 ); + + inst = ((struct PdoExtension *)device->DeviceExtension)->instance; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; + 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: + { + USB_CONFIGURATION_DESCRIPTOR *conf_desc = + urb->u.UrbSelectConfiguration.ConfigurationDescriptor; + usb_dev_handle *husb; + + TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" ); + + husb = usb_open( inst->dev ); + if (husb) + { + int ret; + + ret = usb_set_configuration( husb, + conf_desc->bConfigurationValue ); + if (ret < 0) + ERR( "%s\n", usb_strerror() ); + else + status = STATUS_SUCCESS; + usb_close( husb ); + } + } + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + { + struct _URB_CONTROL_DESCRIPTOR_REQUEST *request = + &urb->u.UrbControlDescriptorRequest; + + TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" ); + + switch (request->DescriptorType) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" ); + if (request->TransferBuffer == NULL) + break; + if (sizeof(USB_DEVICE_DESCRIPTOR) <= request->TransferBufferLength) + { + memcpy( request->TransferBuffer, &inst->dev->descriptor, + sizeof(USB_DEVICE_DESCRIPTOR) ); + status = STATUS_SUCCESS; + } + break; + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" ); + { + unsigned int i, k; + char *buf = request->TransferBuffer; + struct usb_config_descriptor *conf = &inst->dev->config[0]; + struct usb_interface_descriptor *intf; + struct usb_endpoint_descriptor *endp; + int size = request->TransferBufferLength; + + /* FIXME: case of num_altsetting > 1 */ + + if (buf == NULL) + break; + add_data( &buf, &size, conf, + sizeof(USB_CONFIGURATION_DESCRIPTOR) ); + if (size > 0 && conf->extra) + add_data( &buf, &size, conf->extra, conf->extralen ); + for (i = 0; i < conf->bNumInterfaces; ++i) + { + intf = &conf->interface[i].altsetting[0]; + if (size > 0) + add_data( &buf, &size, intf, + sizeof(USB_INTERFACE_DESCRIPTOR) ); + if (size > 0 && intf->extra) + add_data( &buf, &size, intf->extra, intf->extralen ); + for (k = 0; k < intf->bNumEndpoints; ++k) + { + endp = &intf->endpoint[k]; + if (size > 0) + add_data( &buf, &size, endp, + sizeof(USB_ENDPOINT_DESCRIPTOR) ); + if (size > 0 && endp->extra) + add_data( &buf, &size, endp->extra, + endp->extralen ); + } + } + status = STATUS_SUCCESS; + } + break; + default: + FIXME( "unsupported descriptor type %x\n", + request->DescriptorType ); + } + } + break; + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + { + usb_dev_handle *husb; + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request = + &urb->u.UrbControlVendorClassRequest; + + TRACE( "URB_FUNCTION_VENDOR_*\n" ); + + husb = usb_open( inst->dev ); + if (husb) + { + UCHAR req_type = request->RequestTypeReservedBits | (2 << 5); + char *buf; + int ret; + + if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_INTERFACE) + req_type |= 1; + else if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_ENDPOINT) + req_type |= 2; + buf = HeapAlloc( GetProcessHeap(), 0, + request->TransferBufferLength ); + if (buf != NULL) + { + memcpy( buf, request->TransferBuffer, + request->TransferBufferLength ); + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + req_type |= (1 << 7); + ret = usb_control_msg( husb, req_type, request->Request, + request->Value, request->Index, buf, + request->TransferBufferLength, 1000 ); + if (ret < 0) + ERR( "%s\n", usb_strerror() ); + else + { + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + request->TransferBufferLength = + (ret <= request->TransferBufferLength) ? + ret : request->TransferBufferLength; + memcpy( request->TransferBuffer, buf, + request->TransferBufferLength ); + } + status = STATUS_SUCCESS; + } + HeapFree( GetProcessHeap(), 0, buf ); + } + usb_close( husb ); + } + } + break; + default: + FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function ); + } + urb->u.UrbHeader.Status = status; + break; + default: + FIXME( "IOCTL %08x is not implemented\n", + irpsp->Parameters.DeviceIoControl.IoControlCode ); + } + + irp->IoStatus.u.Status = status; + irp->IoStatus.Information = 0; + wine_complete_request( irp, IO_NO_INCREMENT ); + + return status; +} + +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}; + + IO_STACK_LOCATION *irpsp; + NTSTATUS status; + ULONG_PTR info = 0; + + TRACE( "%p, %p\n", device, irp ); + + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; + switch (irpsp->MinorFunction) + { + case IRP_MN_QUERY_DEVICE_RELATIONS: + status = irp->IoStatus.u.Status; + info = irp->IoStatus.Information; + break; + case IRP_MN_QUERY_ID: + switch (irpsp->Parameters.QueryId.IdType) + { + case BusQueryDeviceID: + { + struct PdoExtension *dx = device->DeviceExtension; + WCHAR *device_id = ExAllocatePool( PagedPool, sizeof(device_idW) ); + + if (device_id == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + snprintfW( device_id, strlenW(device_idW) + 1, device_idW, + dx->instance->vid, dx->instance->pid ); + status = STATUS_SUCCESS; + info = (ULONG_PTR)device_id; + break; + } + case BusQueryInstanceID: + { + struct PdoExtension *dx = device->DeviceExtension; + 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->instance_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; + } + + irp->IoStatus.u.Status = status; + irp->IoStatus.Information = info; + wine_complete_request( irp, IO_NO_INCREMENT ); + + return STATUS_SUCCESS; +} + +static BOOL start_service( 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; + } + + ret = StartServiceW( service, 0, NULL ); + if (!ret && ERROR_SERVICE_ALREADY_RUNNING == GetLastError()) + ret = TRUE; + + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + + return ret; +} + +static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst, DRIVER_OBJECT *hubdrv ) +{ + static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\', + 'U','S','B','P','D','O','-','%','u',0}; + + UNICODE_STRING pdo_name; + DEVICE_OBJECT *usbdev = NULL; + WCHAR *buf; + + buf = HeapAlloc( GetProcessHeap(), 0, 30 * sizeof(WCHAR) ); + if (buf == NULL) return NULL; + snprintfW( buf, 30, usbpdoW, last_pdo_num++ ); + RtlInitUnicodeString( &pdo_name, buf ); + + if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name, + 0, 0, FALSE, &usbdev ) == STATUS_SUCCESS) + { + ((struct PdoExtension *)usbdev->DeviceExtension)->instance = inst; + usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE; + usbdev->Flags &= ~DO_DEVICE_INITIALIZING; + } + HeapFree( GetProcessHeap(), 0, buf ); + return usbdev; +} + +static BOOL enum_reg_usb_devices(void) +{ + static const WCHAR usb[] = {'U','S','B',0}; + + 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, usb, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) return FALSE; + + while (SetupDiEnumDeviceInfo( set, i++, &devInfo )) + { + /* get VID and PID */ + SetupDiGetDeviceRegistryPropertyA( set, &devInfo, SPDRP_HARDWAREID, + NULL, NULL, 0, &size ); + buf = HeapAlloc( GetProcessHeap(), 0, size ); + if (buf == NULL) goto fail; + ret = SetupDiGetDeviceRegistryPropertyA( set, &devInfo, SPDRP_HARDWAREID, + NULL, (BYTE *)buf, size, 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 ); + HeapFree( GetProcessHeap(), 0, buf ); + + /* get 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 = strrchr( buf, '\\' ); + 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) goto fail; + + /* 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->dev = NULL; + list_add_tail( &Devices, &instance->entry ); + instance_id = NULL; + } + + SetupDiDestroyDeviceInfoList( set ); + return TRUE; +fail: + if (buf) HeapFree( GetProcessHeap(), 0, buf ); + if (instance_id) 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 ); + } + return FALSE; +} + +static DWORD CALLBACK enum_usb_devices( void *usbhubdrv ) +{ + struct DeviceInstance *instance; + struct usb_device *dev; + struct usb_bus *bus; + DEVICE_OBJECT *pdo; + DRIVER_OBJECT *driver; + DRIVER_OBJECT *hubdrv = usbhubdrv; + NTSTATUS status; + + if (!enum_reg_usb_devices()) + { + ERR( "failed to enumerate USB devices\n" ); + return 1; + } + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + for (bus = usb_busses; bus; bus = bus->next) + for (dev = bus->devices; dev; dev = dev->next) + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->dev == NULL && + dev->descriptor.idVendor == instance->vid && + dev->descriptor.idProduct == instance->pid) + { + if (start_service( instance->service )) + { + pdo = create_pdo( instance, hubdrv ); + if (pdo == NULL) break; + instance->dev = dev; + while (!(driver = __wine_get_driver_object( + instance->service ))) + Sleep( 100 ); + status = __wine_add_device( driver, pdo ); + if (status != STATUS_SUCCESS) break; + __wine_start_device( driver ); + } + break; + } + } + + return 0; +} +#endif + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) +{ +#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H) + HANDLE thread; + + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl; + driver->MajorFunction[IRP_MJ_PNP] = usbhub_dispatch_pnp; + + thread = CreateThread( NULL, 0, enum_usb_devices, driver, 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/usbhub.sys/usbhub.sys.spec b/dlls/usbhub.sys/usbhub.sys.spec new file mode 100644 index 0000000..76421d7 --- /dev/null +++ b/dlls/usbhub.sys/usbhub.sys.spec @@ -0,0 +1 @@ +# nothing to export diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index 9e99985..771c0b0 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -97,6 +97,7 @@ typedef DWORD CONFIGRET; #define CR_INVALID_STRUCTURE_SIZE 0x3b #define NUM_CR_RESULTS 0x3c +#define MAX_DEVICE_ID_LEN 200 #define MAX_CLASS_NAME_LEN 32 #define MAX_GUID_STRING_LEN 39 #define MAX_PROFILE_LEN 80 diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h index 3ad2156..3da8f3c 100644 --- a/include/ddk/ntddk.h +++ b/include/ddk/ntddk.h @@ -61,6 +61,17 @@ typedef struct _CONFIGURATION_INFORMATION ULONG MediumChangerCount; } CONFIGURATION_INFORMATION, *PCONFIGURATION_INFORMATION; + +#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); void WINAPI IoRegisterDriverReinitialization(PDRIVER_OBJECT,PDRIVER_REINITIALIZE,PVOID); diff --git a/include/ddk/usb.h b/include/ddk/usb.h index b8f5f3f..a5db726 100644 --- a/include/ddk/usb.h +++ b/include/ddk/usb.h @@ -82,6 +82,12 @@ typedef PVOID USBD_PIPE_HANDLE; typedef PVOID USBD_CONFIGURATION_HANDLE; typedef PVOID USBD_INTERFACE_HANDLE; +typedef struct _USBD_VERSION_INFORMATION { + ULONG USBDI_Version; + ULONG Supported_USB_Version; +} USBD_VERSION_INFORMATION; +typedef struct _USBD_VERSION_INFORMATION *PUSBD_VERSION_INFORMATION; + typedef enum _USBD_PIPE_TYPE { UsbdPipeTypeControl, UsbdPipeTypeIsochronous, 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 +#include +#include + +#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/usbiodef.h b/include/ddk/usbiodef.h new file mode 100644 index 0000000..15a54fa --- /dev/null +++ b/include/ddk/usbiodef.h @@ -0,0 +1,26 @@ +/* + * 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 FILE_DEVICE_USB FILE_DEVICE_UNKNOWN + +#endif /* __USBIODEF_H__ */ diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 3169153..fd79cb9 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -94,6 +94,11 @@ typedef struct _KMUTANT { UCHAR ApcDisable; } KMUTANT, *PKMUTANT, *RESTRICTED_POINTER PRKMUTANT, KMUTEX, *PKMUTEX, *RESTRICTED_POINTER PRKMUTEX; +typedef struct _KSEMAPHORE { + DISPATCHER_HEADER Header; + LONG Limit; +} KSEMAPHORE, *PKSEMAPHORE, *RESTRICTED_POINTER PRKSEMAPHORE; + typedef enum _KWAIT_REASON { Executive, @@ -202,6 +207,7 @@ typedef struct _WAIT_CONTEXT_BLOCK { #ifndef DEVICE_TYPE #define DEVICE_TYPE ULONG #endif + #define IRP_MJ_MAXIMUM_FUNCTION 0x1b #define IRP_MJ_CREATE 0x00 #define IRP_MJ_CREATE_NAMED_PIPE 0x01 @@ -1008,6 +1014,41 @@ typedef enum _MM_SYSTEM_SIZE MmLargeSystem } MM_SYSTEMSIZE; + +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 { + DevicePropertyDeviceDescription, + DevicePropertyHardwareID, + DevicePropertyCompatibleIDs, + DevicePropertyBootConfiguration, + DevicePropertyBootConfigurationTranslated, + DevicePropertyClassName, + DevicePropertyClassGuid, + DevicePropertyDriverKeyName, + DevicePropertyManufacturer, + DevicePropertyFriendlyName, + DevicePropertyLocationInformation, + DevicePropertyPhysicalDeviceObjectName, + DevicePropertyBusTypeGuid, + DevicePropertyLegacyBusType, + DevicePropertyBusNumber, + DevicePropertyEnumeratorName, + DevicePropertyAddress, + DevicePropertyUINumber, + DevicePropertyInstallState, + DevicePropertyRemovalPolicy +} DEVICE_REGISTRY_PROPERTY; + NTSTATUS WINAPI ObCloseHandle(IN HANDLE handle); #define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.CurrentStackLocation) @@ -1035,6 +1076,7 @@ void WINAPI ExFreePoolWithTag(PVOID,ULONG); NTSTATUS WINAPI IoAllocateDriverObjectExtension(PDRIVER_OBJECT,PVOID,ULONG,PVOID*); PIRP WINAPI IoAllocateIrp(CCHAR,BOOLEAN); +PIRP WINAPI IoBuildDeviceIoControlRequest(ULONG,PDEVICE_OBJECT,PVOID,ULONG,PVOID,ULONG,BOOLEAN,PKEVENT,PIO_STATUS_BLOCK); NTSTATUS WINAPI IoCreateDevice(DRIVER_OBJECT*,ULONG,UNICODE_STRING*,DEVICE_TYPE,ULONG,BOOLEAN,DEVICE_OBJECT**); NTSTATUS WINAPI IoCreateDriver(UNICODE_STRING*,PDRIVER_INITIALIZE); NTSTATUS WINAPI IoCreateSymbolicLink(UNICODE_STRING*,UNICODE_STRING*); @@ -1042,22 +1084,33 @@ void WINAPI IoDeleteDevice(DEVICE_OBJECT*); void WINAPI IoDeleteDriver(DRIVER_OBJECT*); NTSTATUS WINAPI IoDeleteSymbolicLink(UNICODE_STRING*); void WINAPI IoFreeIrp(IRP*); +PDEVICE_OBJECT WINAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT); PEPROCESS WINAPI IoGetCurrentProcess(void); NTSTATUS WINAPI IoGetDeviceObjectPointer(UNICODE_STRING*,ACCESS_MASK,PFILE_OBJECT*,PDEVICE_OBJECT*); +NTSTATUS WINAPI IoGetDeviceProperty(PDEVICE_OBJECT,DEVICE_REGISTRY_PROPERTY,ULONG,PVOID,PULONG); PVOID WINAPI IoGetDriverObjectExtension(PDRIVER_OBJECT,PVOID); PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject(PFILE_OBJECT); void WINAPI IoInitializeIrp(IRP*,USHORT,CCHAR); +void WINAPI IoInvalidateDeviceRelations(PDEVICE_OBJECT,DEVICE_RELATION_TYPE); +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); +LONG WINAPI KeResetEvent(PRKEVENT); +LONG WINAPI KeSetEvent(PRKEVENT,KPRIORITY,BOOLEAN); +KPRIORITY WINAPI KeSetPriorityThread(PKTHREAD, KPRIORITY); +NTSTATUS WINAPI KeWaitForSingleObject(PVOID,KWAIT_REASON,KPROCESSOR_MODE,BOOLEAN,PLARGE_INTEGER); PVOID WINAPI MmAllocateNonCachedMemory(SIZE_T); void WINAPI MmFreeNonCachedMemory(PVOID,SIZE_T); MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void); NTSTATUS WINAPI ObReferenceObjectByHandle(HANDLE,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,PVOID*,POBJECT_HANDLE_INFORMATION); +NTSTATUS WINAPI ObReferenceObjectByPointer(VOID*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE); NTSTATUS WINAPI PsCreateSystemThread(PHANDLE,ULONG,POBJECT_ATTRIBUTES,HANDLE,PCLIENT_ID,PKSTART_ROUTINE,PVOID); #define PsGetCurrentProcess() IoGetCurrentProcess() diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c index bd65654..2d83d24 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 ) @@ -126,7 +133,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; @@ -134,36 +143,38 @@ static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname ) if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; - driver_obj.Size = sizeof(driver_obj); - driver_obj.DriverSection = find_ldr_module( module ); - driver_obj.DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); - driver_obj.DriverExtension = &driver_extension; + driver_obj->Size = sizeof(DRIVER_OBJECT); + driver_obj->DriverSection = find_ldr_module( module ); + driver_obj->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); + driver_obj->DriverExtension = driver_extension; - driver_extension.DriverObject = &driver_obj; - driver_extension.ServiceKeyName = *keyname; + driver_extension->DriverObject = driver_obj; + driver_extension->ServiceKeyName = *keyname; if (WINE_TRACE_ON(relay)) WINE_DPRINTF( "%04x:Call driver init %p (obj=%p,str=%s)\n", GetCurrentThreadId(), - driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer) ); + driver_obj->DriverInit, driver_obj, wine_dbgstr_w(keyname->Buffer) ); - status = driver_obj.DriverInit( &driver_obj, keyname ); + status = driver_obj->DriverInit( driver_obj, keyname ); if (WINE_TRACE_ON(relay)) WINE_DPRINTF( "%04x:Ret driver init %p (obj=%p,str=%s) retval=%08x\n", GetCurrentThreadId(), - driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer), status ); + driver_obj->DriverInit, driver_obj, wine_dbgstr_w(keyname->Buffer), status ); - WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), &driver_obj ); - WINE_TRACE( "- DriverInit = %p\n", driver_obj.DriverInit ); - WINE_TRACE( "- DriverStartIo = %p\n", driver_obj.DriverStartIo ); - WINE_TRACE( "- DriverUnload = %p\n", driver_obj.DriverUnload ); + WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(drv_name), driver_obj ); + WINE_TRACE( "- DriverInit = %p\n", driver_obj->DriverInit ); + WINE_TRACE( "- DriverStartIo = %p\n", driver_obj->DriverStartIo ); + WINE_TRACE( "- DriverUnload = %p\n", driver_obj->DriverUnload ); + WINE_TRACE( "- AddDevice = %p\n", driver_extension->AddDevice ); for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) - WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] ); + WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj->MajorFunction[i] ); return status; } /* load the .sys module for a device driver */ -static BOOL load_driver(void) +static HMODULE load_driver( const WCHAR *drv_name, PDRIVER_OBJECT driver_obj, + PDRIVER_EXTENSION driver_extension ) { static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0}; static const WCHAR postfixW[] = {'.','s','y','s',0}; @@ -175,20 +186,22 @@ static BOOL load_driver(void) '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', '\\','S','e','r','v','i','c','e','s','\\',0}; + HKEY driver_hkey; UNICODE_STRING keypath; HMODULE module; LPWSTR path = NULL, str; DWORD type, size; + NTSTATUS status; - str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(driver_name)*sizeof(WCHAR) ); + str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(drv_name)*sizeof(WCHAR) ); lstrcpyW( str, servicesW ); - lstrcatW( str, driver_name ); + lstrcatW( str, drv_name ); if (RegOpenKeyW( HKEY_LOCAL_MACHINE, str + 18 /* skip \registry\machine */, &driver_hkey )) { WINE_ERR( "cannot open key %s, err=%u\n", wine_dbgstr_w(str), GetLastError() ); HeapFree( GetProcessHeap(), 0, str); - return FALSE; + return NULL; } RtlInitUnicodeString( &keypath, str ); @@ -204,7 +217,7 @@ static BOOL load_driver(void) ExpandEnvironmentStringsW(str,path,size); } HeapFree( GetProcessHeap(), 0, str ); - if (!path) return FALSE; + if (!path) return NULL; } else { @@ -212,11 +225,11 @@ static BOOL load_driver(void) WCHAR buffer[MAX_PATH]; GetSystemDirectoryW(buffer, MAX_PATH); path = HeapAlloc(GetProcessHeap(),0, - (strlenW(buffer) + strlenW(driversW) + strlenW(driver_name) + strlenW(postfixW) + 1) + (strlenW(buffer) + strlenW(driversW) + strlenW(drv_name) + strlenW(postfixW) + 1) *sizeof(WCHAR)); lstrcpyW(path, buffer); lstrcatW(path, driversW); - lstrcatW(path, driver_name); + lstrcatW(path, drv_name); lstrcatW(path, postfixW); } @@ -228,10 +241,32 @@ static BOOL load_driver(void) module = load_driver_module( str ); HeapFree( GetProcessHeap(), 0, path ); - if (!module) return FALSE; + if (!module) return NULL; - init_driver( module, &keypath ); - return TRUE; + status = init_driver( module, &keypath, drv_name, driver_obj, driver_extension ); + if (status != STATUS_SUCCESS) + { + FreeLibrary( module ); + return NULL; + } + return module; +} + +static void unload_driver( HMODULE module, DRIVER_OBJECT *driver_obj ) +{ + if (driver_obj->DriverUnload) + { + if (WINE_TRACE_ON(relay)) + WINE_DPRINTF( "%04x:Call driver unload %p (obj=%p)\n", + GetCurrentThreadId(), driver_obj->DriverUnload, driver_obj ); + + driver_obj->DriverUnload( driver_obj ); + + if (WINE_TRACE_ON(relay)) + WINE_DPRINTF( "%04x:Ret driver unload %p (obj=%p)\n", + GetCurrentThreadId(), driver_obj->DriverUnload, driver_obj ); + } + FreeLibrary( module ); } static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) @@ -256,24 +291,144 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_ SetEvent( stop_event ); return NO_ERROR; default: - WINE_FIXME( "got service ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) ); + WINE_FIXME( "got service ctrl %x for %s\n", ctrl, + wine_dbgstr_w(driver_name) ); status.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( service_handle, &status ); return NO_ERROR; } } +static int loading_request( WCHAR *event_name ) +{ + static WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',0}; + + WCHAR *driver_process_cmd; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + HANDLE pipe; + DWORD count, len; + BOOL ret, loaded; + + /* create winedevice.exe process which will load drivers */ + + len = GetSystemDirectoryW( NULL, 0 ); + driver_process_cmd = HeapAlloc( GetProcessHeap(), 0, sizeof(winedeviceW) + + sizeof(WCHAR) * len ); + if (!driver_process_cmd) return 1; + GetSystemDirectoryW( driver_process_cmd, len ); + strcpyW( driver_process_cmd + len - 1, winedeviceW ); + + RtlZeroMemory( &si, sizeof(STARTUPINFOW) ); + si.cb = sizeof(STARTUPINFOW); + ret = CreateProcessW( NULL, driver_process_cmd, NULL, NULL, FALSE, 0, + NULL, NULL, &si, &pi ); + HeapFree( GetProcessHeap(), 0, driver_process_cmd ); + if (!ret) return 1; + CloseHandle( pi.hThread ); + CloseHandle( pi.hProcess ); + + /* send driver and event names and receive loading result */ + + do { + WaitNamedPipeW( pipe_nameW, NMPWAIT_WAIT_FOREVER ); + pipe = CreateFileW( pipe_nameW, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + } while (pipe == INVALID_HANDLE_VALUE); + len = (strlenW(driver_name) + 1) * sizeof(WCHAR); + ret = WriteFile( pipe, &len, sizeof(DWORD), &count, NULL ); + if (!ret || count != sizeof(DWORD)) goto fail; + ret = WriteFile( pipe, driver_name, len, &count, NULL ); + if (!ret || count != len) goto fail; + ret = WriteFile( pipe, event_name, EVENT_NAME_LEN, &count, NULL ); + if (!ret || count != EVENT_NAME_LEN) goto fail; + ret = ReadFile( pipe, &loaded, sizeof(BOOL), &count, NULL ); + if (!ret || count != sizeof(BOOL)) goto fail; + if (loaded) + { + CloseHandle( pipe ); + return 0; + } +fail: + CloseHandle( pipe ); + return 1; +} + +static HMODULE handle_loading_request( HANDLE pipe, DRIVER_OBJECT *driver_obj, + DRIVER_EXTENSION *driver_extension, + WCHAR **drv_name, WCHAR **event_name ) +{ + HMODULE module = NULL; + BOOL ret, loaded = FALSE; + DWORD count, len; + + *drv_name = NULL; + *event_name = NULL; + ret = ReadFile( pipe, &len, sizeof(DWORD), &count, NULL ); + if (!ret || count != sizeof(DWORD)) goto end; + *drv_name = HeapAlloc( GetProcessHeap(), 0, len ); + if (!*drv_name) goto end; + ret = ReadFile( pipe, *drv_name, len, &count, NULL ); + if (!ret || count != len) goto end; + *event_name = HeapAlloc( GetProcessHeap(), 0, EVENT_NAME_LEN ); + if (!*event_name) goto end; + ret = ReadFile( pipe, *event_name, EVENT_NAME_LEN, &count, NULL ); + if (!ret || count != EVENT_NAME_LEN) goto end; + module = load_driver( *drv_name, driver_obj, driver_extension ); + if (module) loaded = TRUE; + ret = WriteFile( pipe, &loaded, sizeof(BOOL), &count, NULL ); + if (module && (!ret || count != sizeof(BOOL))) + { + unload_driver( module, driver_obj ); + module = NULL; + } +end: + DisconnectNamedPipe( pipe ); + CloseHandle( pipe ); + if (!module) + { + if (*drv_name) HeapFree( GetProcessHeap(), 0, *drv_name ); + if (*event_name) HeapFree( GetProcessHeap(), 0, *drv_name ); + } + return module; +} + +static HANDLE create_named_event( WCHAR **event_name ) +{ + static const WCHAR event_nameW[] = {'_','_','w','i','n','e','_', + 'W','i','n','e','d','e','v','i','c','e','_','%','u',0}; + + HANDLE event; + unsigned int k = 0; + + *event_name = HeapAlloc( GetProcessHeap(), 0, EVENT_NAME_LEN ); + if (!*event_name) return NULL; + for (;;) + { + snprintfW( *event_name, EVENT_NAME_LEN / sizeof(WCHAR), event_nameW, k++ ); + event = CreateEventW( NULL, TRUE, FALSE, *event_name ); + if (event && GetLastError() != ERROR_ALREADY_EXISTS) + return event; + CloseHandle( event ); + } +} + static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) { SERVICE_STATUS status; + WCHAR *event_name; WINE_TRACE( "starting service %s\n", wine_dbgstr_w(driver_name) ); - stop_event = CreateEventW( NULL, TRUE, FALSE, NULL ); - + stop_event = create_named_event( &event_name ); + if (!stop_event) + return; service_handle = RegisterServiceCtrlHandlerExW( driver_name, service_handler, NULL ); if (!service_handle) + { + HeapFree( GetProcessHeap(), 0, event_name ); return; + } status.dwServiceType = SERVICE_WIN32; status.dwCurrentState = SERVICE_START_PENDING; @@ -284,31 +439,100 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) status.dwWaitHint = 10000; SetServiceStatus( service_handle, &status ); - if (load_driver()) + if (!loading_request( event_name )) { status.dwCurrentState = SERVICE_RUNNING; status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; SetServiceStatus( service_handle, &status ); - wine_ntoskrnl_main_loop( stop_event ); + WaitForSingleObject( stop_event, INFINITE ); } else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) ); + HeapFree( GetProcessHeap(), 0, event_name ); status.dwCurrentState = SERVICE_STOPPED; status.dwControlsAccepted = 0; SetServiceStatus( service_handle, &status ); WINE_TRACE( "service %s stopped\n", wine_dbgstr_w(driver_name) ); } -int wmain( int argc, WCHAR *argv[] ) +static DWORD CALLBACK driver_thread( HANDLE pipe ) { - SERVICE_TABLE_ENTRYW service_table[2]; + DRIVER_OBJECT driver_obj; + DRIVER_EXTENSION driver_extension; + WCHAR *drv_name, *event_name; + HMODULE module; - if (!(driver_name = argv[1])) + RtlZeroMemory( &driver_obj, sizeof(driver_obj) ); + RtlZeroMemory( &driver_extension, sizeof(driver_extension) ); + module = handle_loading_request( pipe, &driver_obj, &driver_extension, + &drv_name, &event_name ); + if (module) { - WINE_ERR( "missing device name, winedevice isn't supposed to be run manually\n" ); + HANDLE loop_event; + + loop_event = CreateEventW( NULL, TRUE, FALSE, event_name ); + if (__wine_add_driver_object( &driver_obj, drv_name )) + { + wine_ntoskrnl_main_loop( loop_event ); + __wine_del_driver_object( &driver_obj ); + } + /* stop service if wine_ntoskrnl_main_loop exits */ + SetEvent( loop_event ); + CloseHandle( loop_event ); + unload_driver( module, &driver_obj ); + HeapFree( GetProcessHeap(), 0, drv_name ); + HeapFree( GetProcessHeap(), 0, event_name ); + } + return 0; +} + +static int driver_process(void) +{ + HANDLE pipe, winedevice_mutex, thread; + + __wine_make_process_system(); + winedevice_mutex = CreateMutexW( NULL, TRUE, winedevice_mutexW ); + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + CloseHandle( winedevice_mutex ); return 1; } + for (;;) + { + pipe = CreateNamedPipeW( pipe_nameW, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + 256, 256, 10000, NULL ); + if (pipe == INVALID_HANDLE_VALUE) + { + WINE_ERR( "failed to create pipe\n" ); + continue; + } + if (!ConnectNamedPipe( pipe, NULL ) && + GetLastError() != ERROR_PIPE_CONNECTED) + { + CloseHandle( pipe ); + continue; + } + + thread = CreateThread( NULL, 0, driver_thread, pipe, 0, NULL ); + if (!thread) + { + WINE_ERR( "failed to create thread\n" ); + DisconnectNamedPipe( pipe ); + CloseHandle( pipe ); + continue; + } + CloseHandle( thread ); + } +} + +int wmain( int argc, WCHAR *argv[] ) +{ + SERVICE_TABLE_ENTRYW service_table[2]; + + if (!argv[1]) return driver_process(); + driver_name = argv[1]; service_table[0].lpServiceName = argv[1]; service_table[0].lpServiceProc = ServiceMain; diff --git a/server/device.c b/server/device.c index 4d134a3..acfcd2b 100644 --- a/server/device.c +++ b/server/device.c @@ -32,6 +32,7 @@ #include "file.h" #include "handle.h" #include "request.h" +#include "process.h" struct ioctl_call { @@ -509,6 +510,7 @@ DECL_HANDLER(get_next_device_request) { ioctl = LIST_ENTRY( ptr, struct ioctl_call, mgr_entry ); reply->code = ioctl->code; + reply->pid = get_process_id( ioctl->thread->process ); reply->user_ptr = ioctl->device->user_ptr; reply->in_size = ioctl->in_size; reply->out_size = ioctl->out_size; @@ -554,3 +556,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->handle, 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 a8f3569..803885f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3002,6 +3002,7 @@ enum message_type @REPLY obj_handle_t next; /* handle to the next ioctl */ ioctl_code_t code; /* ioctl code */ + process_id_t pid; /* process id */ client_ptr_t user_ptr; /* opaque ptr for the device */ data_size_t in_size; /* total needed input size */ data_size_t out_size; /* needed output size */ @@ -3115,3 +3116,11 @@ enum message_type unsigned int alpha; /* alpha (0..255) */ unsigned int flags; /* LWA_* flags */ @END + + +/* Get a device name */ +@REQ(get_device_name) + obj_handle_t handle; /* device handle */ +@REPLY + VARARG(name,unicode_str); /* device name */ +@END diff --git a/tools/wine.inf.in b/tools/wine.inf.in index aa82cc1..a0677da 100644 --- a/tools/wine.inf.in +++ b/tools/wine.inf.in @@ -78,10 +78,12 @@ AddReg=\ [DefaultInstall.Services] AddService=MountMgr,0x800,MountMgrService AddService=Spooler,0,SpoolerService +AddService=Usbhub,0,UsbhubService [DefaultInstall.NT.Services] AddService=MountMgr,0x800,MountMgrService AddService=Spooler,0,SpoolerService +AddService=Usbhub,0,UsbhubService [Strings] MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions" @@ -2507,6 +2509,7 @@ HKLM,%CurrentVersion%\Telephony\Country List\998,"SameAreaRule",,"G" 11,,ws2_32.dll 11,,wsock32.dll 12,,mountmgr.sys +12,,usbhub.sys 16422,Internet Explorer,iexplore.exe [SystemIni] @@ -2902,6 +2905,12 @@ StartType=4 ErrorControl=1 LoadOrderGroup="SpoolerGroup" +[UsbhubService] +ServiceBinary="%12%\usbhub.sys" +ServiceType=1 +StartType=2 +ErrorControl=1 + [Services] HKLM,"System\CurrentControlSet\Services\VxD\MSTCP",,,"" -- 1.6.1.3.GIT