From fc2219f93890fdb956f4dcd10605b569ee5ac3e9 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 28 Aug 2009 19:54:50 +0400 Subject: [PATCH 1/2] Add support of native Windows drivers for USB tokens. --- configure.ac | 24 + dlls/mountmgr.sys/device.c | 17 +- dlls/mountmgr.sys/mountmgr.c | 74 ++- dlls/ntoskrnl.exe/Makefile.in | 2 +- dlls/ntoskrnl.exe/ntoskrnl.c | 1525 ++++++++++++++++++++++++++++++++-- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 67 +- dlls/usbd.sys/Makefile.in | 15 + dlls/usbd.sys/usbd.c | 145 ++++ dlls/usbd.sys/usbd.sys.spec | 35 + dlls/usbhub.sys/Makefile.in | 16 + dlls/usbhub.sys/usbhub.c | 1581 +++++++++++++++++++++++++++++++++++ dlls/usbhub.sys/usbhub.sys.spec | 1 + include/cfgmgr32.h | 1 + include/ddk/ntddk.h | 11 + include/ddk/usb.h | 6 + include/ddk/usb100.h | 10 + include/ddk/usbdrivr.h | 28 + include/ddk/usbioctl.h | 90 ++ include/ddk/usbiodef.h | 33 + include/ddk/wdm.h | 81 ++- include/ddk/wdmguid.h | 28 + programs/services/services.c | 21 + programs/winedevice/device.c | 302 ++++++- server/device.c | 25 + server/protocol.def | 9 + tools/wine.inf.in | 9 + 26 files changed, 3975 insertions(+), 181 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/usbioctl.h create mode 100644 include/ddk/usbiodef.h create mode 100644 include/ddk/wdmguid.h diff --git a/configure.ac b/configure.ac index a18083b..695a130 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,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]), @@ -1119,6 +1120,29 @@ 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,"") +AC_SUBST(USBINCL,"") +if test "x$with_usb" != "xno" +then + AC_CHECK_HEADERS([usb.h], + AC_CHECK_LIB(usb, usb_init, + [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb library and header]) + USBLIBS="-lusb"])) + ac_usb_incl=`pkg-config --cflags libusb-1.0` + ac_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$ac_usb_incl $CPPFLAGS" + AC_CHECK_HEADERS([libusb.h], + AC_CHECK_LIB(usb-1.0, libusb_init, + [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb library and header]) + USBLIBS="-lusb-1.0" + AC_SUBST(USBINCL,"$ac_usb_incl")])) + CPPFLAGS="$ac_save_CPPFLAGS" +fi +WINE_NOTICE_WITH(usb,[test "x$ac_cv_lib_usb_usb_init" != "xyes" -a "x$ac_cv_lib_usb_1_0_libusb_init" != "xyes"], + [libusb ${notice_platform}development files not found, USB won't be supported.]) + + dnl **** Check for libgphoto2 **** if test "x$with_gphoto" != "xno" then diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c index d17f878..f284c7b 100644 --- a/dlls/mountmgr.sys/device.c +++ b/dlls/mountmgr.sys/device.c @@ -860,6 +860,7 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; struct disk_device *dev = device->DeviceExtension; + NTSTATUS status; TRACE( "ioctl %x insize %u outsize %u\n", irpsp->Parameters.DeviceIoControl.IoControlCode, @@ -880,31 +881,33 @@ 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(dev->devnum), irpsp->Parameters.DeviceIoControl.OutputBufferLength ); - memcpy( irp->MdlAddress->StartVa, &dev->devnum, len ); + memcpy( irp->AssociatedIrp.SystemBuffer, &dev->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; } LeaveCriticalSection( &device_section ); - return irp->IoStatus.u.Status; + irp->IoStatus.u.Status = status; + IoCompleteRequest( 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 a80d492..d4321b8 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -352,6 +352,7 @@ done: 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 +362,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; + IoCompleteRequest( 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 85efdfe..2a83373 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -25,13 +25,22 @@ #define NONAMELESSUNION #define NONAMELESSSTRUCT +#define INITGUID #include "ntstatus.h" #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 "ddk/wdmguid.h" #include "wine/unicode.h" #include "wine/server.h" #include "wine/list.h" @@ -56,6 +65,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 +75,65 @@ 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; + GUID guid; + int active; +}; + +static struct list InterfaceChangeNotifications = LIST_INIT(InterfaceChangeNotifications); + +struct InterfaceChangeNotification +{ + struct list entry; + GUID interface_class; + PDRIVER_NOTIFICATION_CALLBACK_ROUTINE callback; + void *context; +}; + +struct callback +{ + struct list entry; + PDRIVER_NOTIFICATION_CALLBACK_ROUTINE routine; + void *context; +}; + +static struct list Handles = LIST_INIT(Handles); + +struct HandleInstance +{ + struct list entry; + void *object; + HANDLE handle; + ULONG refs; +}; + #ifdef __i386__ #define DEFINE_FASTCALL1_ENTRYPOINT( name ) \ __ASM_STDCALL_FUNC( name, 4, \ @@ -93,6 +163,192 @@ static inline LPCSTR debugstr_us( const UNICODE_STRING *us ) 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; + } + + do { + ret = StartServiceW( service, 0, NULL ); + if (!ret) + { + if (ERROR_SERVICE_ALREADY_RUNNING == GetLastError()) + ret = TRUE; + else if (ERROR_SERVICE_DATABASE_LOCKED == GetLastError()) + Sleep( 100 ); + else + break; + } + } while (!ret); + + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + + return ret; +} + +/* get name of driver service for device with given id */ +static BOOL get_service( WCHAR *device_id, WCHAR **service_name ) +{ + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + HDEVINFO set; + WCHAR *ptr, *enum_name, *id = NULL; + DWORD size, i = 0; + BOOL ret; + + *service_name = NULL; + ptr = strchrW( device_id, '\\' ); + if (!ptr) return FALSE; + size = ptr - device_id + 1; + enum_name = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ); + if (!enum_name) return FALSE; + lstrcpynW( enum_name, device_id, size ); + + set = SetupDiGetClassDevsW( NULL, enum_name, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) goto end; + while (SetupDiEnumDeviceInfo( set, i++, &devInfo )) + { + SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID, + NULL, NULL, 0, &size ); + if (id) RtlFreeHeap( GetProcessHeap(), 0, id ); + id = RtlAllocateHeap( GetProcessHeap(), 0, size ); + if (!id) break; + ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID, + NULL, (BYTE *)id, size, NULL ); + if (!ret) break; + if (strcmpiW( device_id, id )) continue; + SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE, + NULL, NULL, 0, &size ); + *service_name = RtlAllocateHeap( GetProcessHeap(), 0, size ); + if (!*service_name) break; + ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE, + NULL, (BYTE *)*service_name, size, NULL ); + if (!ret) + { + RtlFreeHeap( GetProcessHeap(), 0, *service_name ); + *service_name = NULL; + break; + } + } + SetupDiDestroyDeviceInfoList( set ); +end: + if (id) RtlFreeHeap( GetProcessHeap(), 0, id ); + if (enum_name) RtlFreeHeap( GetProcessHeap(), 0, enum_name ); + return (*service_name != NULL); +} + +static NTSTATUS get_device_id( DEVICE_OBJECT *pdo, BUS_QUERY_ID_TYPE id_type, + WCHAR **id ) +{ + NTSTATUS status; + IO_STACK_LOCATION *irpsp; + IRP *irp; + + *id = NULL; + irp = IoAllocateIrp( pdo->StackSize, FALSE ); + if (irp == NULL) return STATUS_NO_MEMORY; + irpsp = 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 = IoCallDriver( pdo, irp ); + if (status == STATUS_SUCCESS) + *id = (WCHAR *)irp->IoStatus.Information; + IoFreeIrp( irp ); + return status; +} + +static BOOL compare_ids( WCHAR *hardware_id, WCHAR *instance_id, + WCHAR *device_instance_id ) +{ + WCHAR *ptr, *ptr2; + + ptr = strrchrW( device_instance_id, '\\' ); + if (ptr == NULL) return FALSE; + if (strncmpiW( hardware_id, device_instance_id, ptr - device_instance_id )) + return FALSE; + ++ptr; + ptr2 = strrchrW( ptr, '&' ); + ptr2 = ptr2 ? (ptr2 + 1) : ptr; + if (strcmpiW( instance_id, ptr2 )) + return FALSE; + return TRUE; +} + +/* caller is responsible for proper locking to prevent modifying Interfaces list */ +static struct InterfaceInstance *get_registered_interface( WCHAR *name, USHORT len ) +{ + struct InterfaceInstance *interf; + + LIST_FOR_EACH_ENTRY( interf, &Interfaces, struct InterfaceInstance, entry ) + { + if (!strncmpW( name, interf->link, len )) + return interf; + } + return NULL; +} + +static void call_interface_change_callbacks( const GUID *interface_class, + UNICODE_STRING *link_name ) +{ + struct list callbacks = LIST_INIT(callbacks); + struct InterfaceChangeNotification *notification; + struct callback *cb, *cb2; + DEVICE_INTERFACE_CHANGE_NOTIFICATION change_notification; + NTSTATUS callback_status; + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( notification, &InterfaceChangeNotifications, + struct InterfaceChangeNotification, entry ) + { + if (!memcmp( interface_class, ¬ification->interface_class, + sizeof(*interface_class) )) + { + cb = HeapAlloc( GetProcessHeap(), 0, sizeof(*cb) ); + if (cb == NULL) break; + cb->routine = notification->callback; + cb->context = notification->context; + list_add_tail( &callbacks, &cb->entry ); + } + } + LeaveCriticalSection( &cs ); + + change_notification.Version = 1; + change_notification.Size = sizeof(change_notification); + change_notification.Event = GUID_DEVICE_INTERFACE_ARRIVAL; + change_notification.InterfaceClassGuid = *interface_class; + change_notification.SymbolicLinkName = link_name; + + LIST_FOR_EACH_ENTRY_SAFE( cb, cb2, &callbacks, struct callback, entry ) + { + if (TRACE_ON(relay)) + DPRINTF( "%04x:Call callback %p (notification=%p,context=%p)\n", + GetCurrentThreadId(), cb->routine, &change_notification, + cb->context ); + + callback_status = cb->routine( &change_notification, cb->context ); + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Ret callback %p (notification=%p,context=%p) retval=%08x\n", + GetCurrentThreadId(), cb->routine, &change_notification, + cb->context, callback_status ); + + list_remove( &cb->entry ); + HeapFree( GetProcessHeap(), 0, cb ); + } +} + static HANDLE get_device_manager(void) { static HANDLE device_manager; @@ -121,6 +377,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 ) { @@ -142,61 +433,79 @@ 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; + PFILE_OBJECT file; NTSTATUS status; LARGE_INTEGER count; + IO_STATUS_BLOCK iosb; TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size ); - /* 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; + file = ExAllocatePool( NonPagedPool, sizeof(*file) ); + if (file == NULL) + return STATUS_NO_MEMORY; + irp = IoBuildDeviceIoControlRequest( code, device, in_buff, in_size, + out_buff, *out_size, FALSE, NULL, &iosb ); + if (irp == NULL) + { + ExFreePool( file ); + return STATUS_NO_MEMORY; + } + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + irp->RequestorMode = UserMode; + irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + irp->Tail.Overlay.OriginalFileObject = file; + device->CurrentIrp = irp; + file->Type = IO_TYPE_FILE; + file->Size = sizeof(*file); + file->DeviceObject = device; KeQueryTickCount( &count ); /* update the global KeTickCount */ - - 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 = IoCallDriver( device, irp ); + *out_size = (status >= 0) ? iosb.Information : 0; + return status; } @@ -213,6 +522,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 ))) { @@ -236,6 +546,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; @@ -249,12 +560,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: @@ -276,6 +591,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 (!strcmpiW( drv->service, service )) + { + driver_obj = drv->driver; + break; + } + } + LeaveCriticalSection( &cs ); + return driver_obj; +} + + +/*********************************************************************** + * __wine_add_device (Not a Windows API) + */ +NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev ) +{ + NTSTATUS status; + NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) = + driver->DriverExtension->AddDevice; + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Call AddDevice %p (%p,%p)\n", + GetCurrentThreadId(), AddDevice, driver, dev ); + + status = AddDevice( driver, dev ); + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Ret AddDevice %p (%p,%p) retval=%08x\n", + GetCurrentThreadId(), AddDevice, driver, dev, status ); + + return status; +} + + +/*********************************************************************** + * __wine_start_device (Not a Windows API) + */ +NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device ) +{ + DRIVER_OBJECT *driver = device->DriverObject; + IO_STACK_LOCATION *irpsp; + PIRP irp; + NTSTATUS status; + + if (driver->MajorFunction[IRP_MJ_PNP] == NULL) + return STATUS_NOT_SUPPORTED; + irp = IoAllocateIrp( device->StackSize, FALSE ); + if (irp == NULL) return STATUS_NO_MEMORY; + + irpsp = 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 = IoCallDriver( device, irp ); + IoFreeIrp( irp ); + return status; +} + + +/*********************************************************************** + * ExAcquireFastMutexUnsafe (NTOSKRNL.EXE.@) + */ +#ifdef DEFINE_FASTCALL1_ENTRYPOINT +DEFINE_FASTCALL1_ENTRYPOINT( ExAcquireFastMutexUnsafe ) +void WINAPI __regs_ExAcquireFastMutexUnsafe( PFAST_MUTEX FastMutex ) +#else +void WINAPI ExAcquireFastMutexUnsafe( PFAST_MUTEX FastMutex ) +#endif +{ + FIXME( "stub: %p\n", FastMutex ); +} + + +/*********************************************************************** + * ExReleaseFastMutexUnsafe (NTOSKRNL.EXE.@) + */ +#ifdef DEFINE_FASTCALL1_ENTRYPOINT +DEFINE_FASTCALL1_ENTRYPOINT( ExReleaseFastMutexUnsafe ) +void WINAPI __regs_ExReleaseFastMutexUnsafe( PFAST_MUTEX FastMutex ) +#else +void WINAPI ExReleaseFastMutexUnsafe( PFAST_MUTEX FastMutex ) +#endif +{ + FIXME( "stub: %p\n", FastMutex ); +} + + +/*********************************************************************** + * IoAcquireCancelSpinLock (NTOSKRNL.EXE.@) + */ +void WINAPI IoAcquireCancelSpinLock( PKIRQL Irql ) +{ + FIXME( "stub: %p\n", Irql ); +} + +/*********************************************************************** + * IoReleaseCancelSpinLock (NTOSKRNL.EXE.@) + */ +void WINAPI IoReleaseCancelSpinLock( KIRQL Irql ) +{ + FIXME( "stub: %u\n", Irql ); +} + +/*********************************************************************** * IoAllocateDriverObjectExtension (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject, @@ -283,11 +756,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.@) @@ -295,10 +788,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.@) @@ -378,12 +885,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 ) @@ -422,6 +990,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, @@ -435,23 +1005,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; } @@ -514,6 +1120,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 ); @@ -521,6 +1128,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; @@ -535,7 +1153,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; @@ -548,6 +1170,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; } @@ -601,6 +1225,198 @@ 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 = IoCallDriver( DeviceObject, irp ); + rel = (DEVICE_RELATIONS *)irp->IoStatus.Information; + if (status == STATUS_SUCCESS && rel && rel->Count) + { + unsigned int k; + + for (k = 0; k < rel->Count; ++k) + { + IoFreeIrp( irp ); + irp = IoAllocateIrp( rel->Objects[k]->StackSize, FALSE ); + if (irp == NULL) return; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1; + irpsp->MajorFunction = IRP_MJ_PNP; + irpsp->MinorFunction = IRP_MN_QUERY_ID; + irpsp->Parameters.QueryId.IdType = BusQueryDeviceID; + status = IoCallDriver( rel->Objects[k], irp ); + if (status == STATUS_SUCCESS) + { + WCHAR *service; + + if (get_service( (WCHAR *)irp->IoStatus.Information, &service ) + && start_service( service )) + { + DRIVER_OBJECT *driver; + + while (!(driver = __wine_get_driver_object( service ))) + Sleep( 100 ); + status = __wine_add_device( driver, rel->Objects[k] ); + if (status == STATUS_SUCCESS && + rel->Objects[k]->AttachedDevice) + __wine_start_device( rel->Objects[k]->AttachedDevice ); + } + if (service) RtlFreeHeap( GetProcessHeap(), 0, service ); + } + ExFreePool( (void *)irp->IoStatus.Information ); + } + ExFreePool( rel ); + } + IoFreeIrp( irp ); + } + else + FIXME( "DEVICE_RELATION_TYPE %u not implemented\n", Type ); +} + + +/*********************************************************************** + * 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; + } + detail->DevicePath[1] = '?'; + strcpyW( interf->link, detail->DevicePath ); + target = RtlAllocateHeap( GetProcessHeap(), 0, + MAX_PATH * sizeof(WCHAR) ); + if (target == NULL) + { + RtlFreeHeap( GetProcessHeap(), 0, interf->link ); + RtlFreeHeap( GetProcessHeap(), 0, interf ); + break; + } + status = IoGetDeviceProperty( PhysicalDeviceObject, + DevicePropertyPhysicalDeviceObjectName, + MAX_PATH * sizeof(WCHAR), target, &size ); + if (status == STATUS_SUCCESS) + { + RtlInitUnicodeString( &interf->target, target ); + interf->guid = *InterfaceClassGuid; + interf->active = 0; + EnterCriticalSection( &cs ); + if (!get_registered_interface( interf->link, + strlenW(interf->link) )) + { + list_add_tail( &Interfaces, &interf->entry ); + LeaveCriticalSection( &cs ); + break; + } + LeaveCriticalSection( &cs ); + } + RtlFreeHeap( GetProcessHeap(), 0, target ); + RtlFreeHeap( GetProcessHeap(), 0, interf->link ); + RtlFreeHeap( GetProcessHeap(), 0, interf ); + } + break; + } + SetupDiDestroyDeviceInfoList( set ); + + if (STATUS_SUCCESS == status) + RtlCreateUnicodeString( SymbolicLinkName, detail->DevicePath ); +end: + if (detail) RtlFreeHeap( GetProcessHeap(), 0, detail ); + if (id) RtlFreeHeap( GetProcessHeap(), 0, id ); + if (enumerator) RtlFreeHeap( GetProcessHeap(), 0, enumerator ); + if (hardware_id) ExFreePool( hardware_id ); + if (instance_id) ExFreePool( instance_id ); + return status; +} + +/*********************************************************************** * IoDeleteSymbolicLink (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name ) @@ -631,6 +1447,51 @@ 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; + GUID guid; + int changed = 0; + + status = STATUS_OBJECT_NAME_NOT_FOUND; + EnterCriticalSection( &cs ); + interf = get_registered_interface( SymbolicLinkName->Buffer, + SymbolicLinkName->Length / sizeof(WCHAR) ); + if (interf != NULL) + { + if (!interf->active) + { + guid = interf->guid; + status = IoCreateSymbolicLink( SymbolicLinkName, &interf->target ); + if (status == STATUS_SUCCESS) + { + interf->active = 1; + changed = 1; + } + } + else status = STATUS_SUCCESS; + } + LeaveCriticalSection( &cs ); + if (changed) call_interface_change_callbacks( &guid, SymbolicLinkName ); + return status; + } + else + { + FIXME( "Disabling interface is not supported\n" ); + return STATUS_NOT_IMPLEMENTED; + } +} + + +/*********************************************************************** * IoGetDeviceObjectPointer (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK access, PFILE_OBJECT *file, PDEVICE_OBJECT *device ) @@ -641,14 +1502,74 @@ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK acc /*********************************************************************** - * IofCallDriver (NTOSKRNL.EXE.@) + * IoGetDeviceProperty (NTOSKRNL.EXE.@) */ -#ifdef DEFINE_FASTCALL2_ENTRYPOINT -DEFINE_FASTCALL2_ENTRYPOINT( IofCallDriver ) -NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) -#else -NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) -#endif +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 DevicePropertyHardwareID: + { + WCHAR *hardware_id; + + status = get_device_id( DeviceObject, BusQueryDeviceID, &hardware_id ); + if (status != STATUS_SUCCESS) break; + *ResultLength = (strlenW(hardware_id) + 1) * sizeof(WCHAR); + if (BufferLength >= *ResultLength) + strcpyW( PropertyBuffer, hardware_id ); + else + status = STATUS_BUFFER_TOO_SMALL; + ExFreePool( hardware_id ); + break; + } + 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; + + if (status != STATUS_SUCCESS) break; + *ResultLength = len + sizeof(device); + if (BufferLength >= *ResultLength) + { + strcpyW( PropertyBuffer, device ); + device_name[len / sizeof(WCHAR)] = 0; + strcatW( PropertyBuffer, device_name ); + } + else status = STATUS_BUFFER_TOO_SMALL; + break; + } + default: + FIXME( "device property %u is not supported\n", DeviceProperty ); + status = STATUS_NOT_IMPLEMENTED; + } + + return status; +} + + +/*********************************************************************** + * IoCallDriver (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoCallDriver( DEVICE_OBJECT *device, IRP *irp ) { PDRIVER_DISPATCH dispatch; IO_STACK_LOCATION *irpsp; @@ -658,14 +1579,46 @@ NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) --irp->CurrentLocation; irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation; + irpsp->DeviceObject = device; 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; } /*********************************************************************** + * IofCallDriver (NTOSKRNL.EXE.@) + */ +#ifdef DEFINE_FASTCALL2_ENTRYPOINT +DEFINE_FASTCALL2_ENTRYPOINT( IofCallDriver ) +NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) +#else +NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) +#endif +{ + return IoCallDriver( device, irp ); +} + +/*********************************************************************** + * IoGetAttachedDeviceReference (NTOSKRNL.EXE.@) + */ +PDEVICE_OBJECT WINAPI IoGetAttachedDeviceReference( PDEVICE_OBJECT obj ) +{ + FIXME( "stub: %p\n", obj ); + return obj; +} + +/*********************************************************************** * IoGetRelatedDeviceObject (NTOSKRNL.EXE.@) */ PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject( PFILE_OBJECT obj ) @@ -709,6 +1662,97 @@ void WINAPI IoRegisterDriverReinitialization( PDRIVER_OBJECT obj, PDRIVER_REINIT /*********************************************************************** + * IoRegisterPlugPlayNotification (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoRegisterPlugPlayNotification( IO_NOTIFICATION_EVENT_CATEGORY + EventCategory, + ULONG EventCategoryFlags, + PVOID EventCategoryData, + PDRIVER_OBJECT DriverObject, + PDRIVER_NOTIFICATION_CALLBACK_ROUTINE + CallbackRoutine, PVOID Context, + PVOID *NotificationEntry ) +{ + TRACE( "%u %u %p %p %p %p %p\n", EventCategory, EventCategoryFlags, + EventCategoryData, DriverObject, CallbackRoutine, Context, + NotificationEntry ); + + if (EventCategory == EventCategoryDeviceInterfaceChange) + { + struct InterfaceChangeNotification *notification = + HeapAlloc( GetProcessHeap(), 0, sizeof(*notification) ); + struct list interfs = LIST_INIT(interfs); + struct InterfaceInstance *interf, *interf2; + UNICODE_STRING link; + + if (notification == NULL) return STATUS_NO_MEMORY; + notification->interface_class = *(GUID *)EventCategoryData; + notification->callback = CallbackRoutine; + notification->context = Context; + + EnterCriticalSection( &cs ); + list_add_tail( &InterfaceChangeNotifications, ¬ification->entry ); + if (EventCategoryFlags & PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES) + { + LIST_FOR_EACH_ENTRY( interf, &Interfaces, struct InterfaceInstance, entry ) + { + if (interf->active && !memcmp( ¬ification->interface_class, + &interf->guid, sizeof(GUID) )) + { + interf2 = HeapAlloc( GetProcessHeap(), 0, sizeof(*interf2) ); + if (interf2 == NULL) break; + interf2->link = HeapAlloc( GetProcessHeap(), 0, + (strlenW(interf->link) + 1) * sizeof(WCHAR) ); + if (interf2->link == NULL) break; + strcpyW( interf2->link, interf->link ); + interf2->guid = interf->guid; + list_add_tail( &interfs, &interf2->entry ); + } + } + } + LeaveCriticalSection( &cs ); + + LIST_FOR_EACH_ENTRY_SAFE( interf, interf2, &interfs, + struct InterfaceInstance, entry ) + { + list_remove( &interf->entry ); + if (interf->link) + { + RtlInitUnicodeString( &link, interf->link ); + call_interface_change_callbacks( &interf->guid, &link ); + HeapFree( GetProcessHeap(), 0, interf->link ); + } + HeapFree( GetProcessHeap(), 0, interf ); + } + *NotificationEntry = notification; + return STATUS_SUCCESS; + } + else + { + FIXME( "event category %u is not supported\n", EventCategory ); + return STATUS_NOT_IMPLEMENTED; + } +} + + +/*********************************************************************** + * IoUnregisterPlugPlayNotification (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoUnregisterPlugPlayNotification( PVOID NotificationEntry ) +{ + struct InterfaceChangeNotification *notification = NotificationEntry; + + TRACE( "%p\n", NotificationEntry ); + + EnterCriticalSection( &cs ); + list_remove( ¬ification->entry ); + LeaveCriticalSection( &cs ); + HeapFree( GetProcessHeap(), 0, notification ); + return STATUS_SUCCESS; +} + + +/*********************************************************************** * IoRegisterShutdownNotification (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoRegisterShutdownNotification( PDEVICE_OBJECT obj ) @@ -732,20 +1776,16 @@ NTSTATUS WINAPI IoReportResourceUsage(PUNICODE_STRING name, PDRIVER_OBJECT drv_o /*********************************************************************** - * IofCompleteRequest (NTOSKRNL.EXE.@) + * IoCompleteRequest (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 +void WINAPI IoCompleteRequest( 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 ); @@ -770,28 +1810,61 @@ void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost ) if (call_flag) { TRACE( "calling %p( %p, %p, %p )\n", routine, - irpsp->DeviceObject, irp, irpsp->Context ); - stat = routine( irpsp->DeviceObject, irp, irpsp->Context ); + (irpsp + 1)->DeviceObject, irp, irpsp->Context ); + stat = routine( (irpsp + 1)->DeviceObject, irp, irpsp->Context ); TRACE( "CompletionRoutine returned %x\n", stat ); if (STATUS_MORE_PROCESSING_REQUIRED == stat) return; } } - if (iosb && STATUS_SUCCESS == status) + if (iosb && status >= 0) { iosb->u.Status = irp->IoStatus.u.Status; iosb->Information = irp->IoStatus.Information; } + event = irp->UserEvent; + EnterCriticalSection( &cs ); LIST_FOR_EACH_ENTRY( instance, &Irps, struct IrpInstance, entry ) { if (instance->irp == irp) { + void *buf = irp->AssociatedIrp.SystemBuffer; + MDL *mdl = irp->MdlAddress; + struct _FILE_OBJECT *file = irp->Tail.Overlay.OriginalFileObject; + list_remove( &instance->entry ); HeapFree( GetProcessHeap(), 0, instance ); + if (mdl) + { + ExFreePool( mdl ); + } + else if (buf) + { + memcpy( irp->UserBuffer, buf, irp->IoStatus.Information ); + ExFreePool( buf ); + } + if (file) ExFreePool( file ); IoFreeIrp( irp ); break; } } + LeaveCriticalSection( &cs ); + if (event) + KeSetEvent( event, 0, FALSE ); +} + + +/*********************************************************************** + * 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 IoCompleteRequest( irp, priority_boost ); } @@ -971,20 +2044,131 @@ NTSTATUS WINAPI FsRtlRegisterUncProvider(PHANDLE MupHandle, PUNICODE_STRING Redi } /*********************************************************************** + * 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 ) { - FIXME( "stub: %p %d %d\n", Event, Type, 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) { - FIXME( "stub: %p, %u\n", Mutex, Level ); + TRACE( "%p, %u\n", Mutex, Level ); + RtlZeroMemory( Mutex, sizeof(KMUTEX) ); + Mutex->Header.Type = 2; + Mutex->Header.Size = 8; + Mutex->Header.SignalState = 1; + InitializeListHead( &Mutex->Header.WaitListHead ); + Mutex->ApcDisable = 1; +} + + +/*********************************************************************** + * 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 %d\n", Semaphore, Increment, Adjustment, Wait); + return 0; } @@ -998,11 +2182,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; } @@ -1080,6 +2277,16 @@ 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, @@ -1088,8 +2295,84 @@ NTSTATUS WINAPI KeWaitForSingleObject(PVOID Object, BOOLEAN Alertable, PLARGE_INTEGER Timeout) { - FIXME( "stub: %p, %d, %d, %d, %p\n", Object, WaitReason, WaitMode, Alertable, Timeout ); - return STATUS_NOT_IMPLEMENTED; + DISPATCHER_HEADER *header = Object; + NTSTATUS status = STATUS_SUCCESS; + + TRACE( "%p, %d, %d, %d, %p\n", Object, WaitReason, WaitMode, Alertable, Timeout ); + + switch (header->Type) + { + case NotificationEvent: + case SynchronizationEvent: + { + struct HandleInstance *inst; + HANDLE event_handle = NULL; + + if (InterlockedCompareExchange( &header->SignalState, 0, header->Type )) + { + status = STATUS_SUCCESS; + break; + } + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry ) + { + if (inst->object == Object) + { + event_handle = inst->handle; + ++inst->refs; + break; + } + } + while (event_handle == NULL) + { + OBJECT_ATTRIBUTES attr; + + RtlZeroMemory( &attr, sizeof(attr) ); + attr.Length = sizeof(attr); + status = NtCreateEvent( &event_handle, EVENT_ALL_ACCESS, &attr, + !header->Type, FALSE ); + if (status != STATUS_SUCCESS) + break; + inst = HeapAlloc( GetProcessHeap(), 0, sizeof(*inst) ); + if (inst == NULL) + { + NtClose( event_handle ); + status = STATUS_NO_MEMORY; + break; + } + inst->object = Object; + inst->handle = event_handle; + inst->refs = 1; + list_add_head( &Handles, &inst->entry ); + } + LeaveCriticalSection( &cs ); + if (status != STATUS_SUCCESS) + break; + + status = NtWaitForSingleObject( event_handle, Alertable, Timeout ); + + EnterCriticalSection( &cs ); + LIST_FOR_EACH_ENTRY( inst, &Handles, struct HandleInstance, entry ) + { + if (inst->object == Object) + { + if (!--inst->refs) + { + list_remove( &inst->entry ); + NtClose( inst->handle ); + HeapFree( GetProcessHeap(), 0, inst ); + } + break; + } + } + LeaveCriticalSection( &cs ); + break; + } + default: + WARN( "synchronization object %u is not supported\n", header->Type ); + } + return status; } /*********************************************************************** @@ -1146,6 +2429,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.@) */ @@ -1156,6 +2449,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) @@ -1183,6 +2486,35 @@ NTSTATUS WINAPI ObReferenceObjectByHandle( HANDLE obj, ACCESS_MASK access, return STATUS_NOT_IMPLEMENTED; } +/*********************************************************************** + * MmUnmapLockedPages (NTOSKRNL.EXE.@) + */ +void WINAPI MmUnmapLockedPages(PVOID BaseAddress, PMDL MemoryDescriptorList) +{ + TRACE("%p %p\n", BaseAddress, MemoryDescriptorList); +} + + +/*********************************************************************** + * ObReferenceObjectByPointer (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI ObReferenceObjectByPointer( VOID *obj, ACCESS_MASK access, + POBJECT_TYPE type, + KPROCESSOR_MODE mode ) +{ + FIXME( "stub: %p %x %p %d\n", obj, access, type, mode ); + return STATUS_NOT_IMPLEMENTED; +} + + +/*********************************************************************** + * ObDereferenceObject (NTOSKRNL.EXE.@) + */ +void WINAPI ObDereferenceObject( VOID *obj ) +{ + FIXME( "stub: %p\n", obj ); +} + /*********************************************************************** * ObfDereferenceObject (NTOSKRNL.EXE.@) @@ -1194,11 +2526,19 @@ void WINAPI __regs_ObfDereferenceObject( VOID *obj ) void WINAPI ObfDereferenceObject( VOID *obj ) #endif { - FIXME( "stub: %p\n", obj ); + ObDereferenceObject( obj ); } /*********************************************************************** + * MmUnlockPages (NTOSKRNL.EXE.@) + */ +void WINAPI MmUnlockPages(PMDL MemoryDescriptorList) +{ + FIXME("stub: %p\n", MemoryDescriptorList); +} + +/*********************************************************************** * PsCreateSystemThread (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess, @@ -1334,6 +2674,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) { @@ -1341,9 +2683,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 fa793eb..1bf5cfb 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 @@ -323,7 +323,7 @@ @ stdcall IoBuildDeviceIoControlRequest(long ptr ptr long ptr long long ptr ptr) @ stub IoBuildPartialMdl @ stub IoBuildSynchronousFsdRequest -@ stub IoCallDriver +@ stdcall IoCallDriver(ptr ptr) @ stub IoCancelFileOpen @ stub IoCancelIrp @ stub IoCheckDesiredAccess @@ -333,7 +333,7 @@ @ stub IoCheckQuerySetVolumeInformation @ stub IoCheckQuotaBufferValidity @ stub IoCheckShareAccess -@ stub IoCompleteRequest +@ stdcall IoCompleteRequest(ptr long) @ stub IoConnectInterrupt @ stub IoCreateController @ stdcall IoCreateDevice(ptr long ptr long long long ptr) @@ -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 @ stdcall IoInitializeTimer(ptr ptr ptr) -@ 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) @ stdcall IoRegisterFileSystem(ptr) @ stub IoRegisterFsRegistrationChange @ stub IoRegisterLastChanceShutdownNotification -@ stub IoRegisterPlugPlayNotification +@ stdcall IoRegisterPlugPlayNotification(long long ptr ptr ptr ptr ptr) @ stdcall IoRegisterShutdownNotification(ptr) -@ stub IoReleaseCancelSpinLock +@ stdcall IoReleaseCancelSpinLock(long) @ stub IoReleaseRemoveLockAndWaitEx @ stub IoReleaseRemoveLockEx @ stub IoReleaseVpbSpinLock @@ -446,7 +446,7 @@ @ stub IoRequestDeviceEject @ stub IoReuseIrp @ stub IoSetCompletionRoutineEx -@ stub IoSetDeviceInterfaceState +@ stdcall IoSetDeviceInterfaceState(ptr long) @ stub IoSetDeviceToVerify @ stub IoSetFileOrigin @ stub IoSetHardErrorOrVerifyDevice @@ -469,7 +469,7 @@ @ stub IoThreadToProcess @ stdcall IoUnregisterFileSystem(ptr) @ stub IoUnregisterFsRegistrationChange -@ stub IoUnregisterPlugPlayNotification +@ stdcall IoUnregisterPlugPlayNotification(ptr) @ stub IoUnregisterShutdownNotification @ stub IoUpdateShareAccess @ stub IoValidateDeviceIoControlAccess @@ -515,10 +515,10 @@ @ stub KeBugCheckEx @ stub KeCancelTimer @ stub KeCapturePersistentThreadState -@ stub KeClearEvent +@ stdcall KeClearEvent(ptr) @ stub KeConnectInterrupt @ stub KeDcacheFlushCount -@ stub KeDelayExecutionThread +@ stdcall KeDelayExecutionThread(long long ptr) @ stub KeDeregisterBugCheckCallback @ stub KeDeregisterBugCheckReasonCallback @ stub KeDetachProcess @@ -529,7 +529,7 @@ @ stub KeFindConfigurationNextEntry @ stub KeFlushEntireTb @ stub KeFlushQueuedDpcs -@ stub KeGetCurrentThread +@ stdcall KeGetCurrentThread() @ stub KeGetPreviousMode @ stub KeGetRecommendedSharedDataAlignment @ stub KeI386AbiosCall @@ -551,7 +551,7 @@ @ stub KeInitializeMutant @ 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 @@ -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 @@ -798,7 +798,7 @@ @ stub ObCloseHandle @ stub ObCreateObject @ stub ObCreateObjectType -@ stub ObDereferenceObject +@ stdcall ObDereferenceObject(ptr) @ stub ObDereferenceSecurityDescriptor @ stub ObFindHandleForObject @ stub ObGetObjectSecurity @@ -811,7 +811,7 @@ @ stub ObQueryObjectAuditingByHandle @ stdcall ObReferenceObjectByHandle(long long ptr long ptr ptr) @ 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,8 @@ # or 'wine_' (for user-visible functions) to avoid namespace conflicts. @ cdecl wine_ntoskrnl_main_loop(long) +@ cdecl __wine_add_device(ptr ptr) +@ cdecl __wine_add_driver_object(ptr wstr) +@ cdecl __wine_del_driver_object(ptr) +@ cdecl __wine_get_driver_object(wstr) +@ cdecl __wine_start_device(ptr) 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..a04b8cc --- /dev/null +++ b/dlls/usbhub.sys/Makefile.in @@ -0,0 +1,16 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = usbhub.sys +IMPORTS = ntoskrnl.exe kernel32 advapi32 setupapi ntdll +EXTRADLLFLAGS = -Wb,--subsystem,native +EXTRAINCL = @USBINCL@ +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..8568b9c --- /dev/null +++ b/dlls/usbhub.sys/usbhub.c @@ -0,0 +1,1581 @@ +/* + * Copyright 2008-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 + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include + +#ifdef HAVE_LIBUSB_H +#include +#elif defined(HAVE_USB_H) +#include +#endif + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#define INITGUID + +#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 "devguid.h" +#include "ddk/ntddk.h" +#include "ddk/usbdrivr.h" +#include "ddk/usbioctl.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(usbhub); + +extern NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev ); +extern DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service ); +extern NTSTATUS CDECL __wine_start_device( DEVICE_OBJECT *device ); + +#define NUMBER_OF_PORTS 8 + +static const WCHAR usbW[] = {'U','S','B',0}; + +static struct list Devices = LIST_INIT(Devices); + +struct DeviceInstance +{ + struct list entry; + USHORT vid; + USHORT pid; + char *instance_id; + WCHAR *service; +#ifdef HAVE_LIBUSB_H + libusb_device *dev; +#else + struct usb_device *dev; +#endif +}; + +struct PdoExtension +{ + struct DeviceInstance *instance; +}; + +#ifdef HAVE_LIBUSB + +static void add_data( unsigned char **dst, ULONG *dst_size, const void *src, ULONG src_size ) +{ + int copy; + + copy = (src_size >= *dst_size) ? *dst_size : src_size; + memcpy( *dst, src, copy ); + *dst += copy; + *dst_size -= copy; +} + +static NTSTATUS WINAPI usbhub_ioctl( 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 = STATUS_UNSUCCESSFUL; + struct DeviceInstance *inst; + ULONG_PTR info = 0; + + TRACE( "%p, %p\n", device, irp ); + + inst = ((struct PdoExtension *)device->DeviceExtension)->instance; + if (inst->service) goto done; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; + + switch (irpsp->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_USB_GET_NODE_INFORMATION: + { + USB_NODE_INFORMATION *node_info = irp->AssociatedIrp.SystemBuffer; + + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*node_info)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + RtlZeroMemory( node_info, sizeof(*node_info) ); + node_info->u.HubInformation.HubDescriptor.bDescriptorLength = 9; + node_info->u.HubInformation.HubDescriptor.bDescriptorType = 41; + node_info->u.HubInformation.HubDescriptor.bNumberOfPorts = NUMBER_OF_PORTS; + status = STATUS_SUCCESS; + info = sizeof(*node_info); + break; + } + case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION: + { + USB_NODE_CONNECTION_INFORMATION *conn_info = irp->AssociatedIrp.SystemBuffer; + ULONG index = 0; +#ifdef HAVE_LIBUSB_H + struct DeviceInstance *instance; + uint8_t bus_number = libusb_get_bus_number( inst->dev ); +#else + struct usb_device *dev; +#endif + + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*conn_info)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + if (!conn_info->ConnectionIndex || conn_info->ConnectionIndex > NUMBER_OF_PORTS) + { + status = STATUS_INVALID_PARAMETER; + break; + } + RtlZeroMemory( (ULONG *)conn_info + 1, sizeof(*conn_info) - sizeof(ULONG) ); +#ifdef HAVE_LIBUSB_H + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->dev && instance->dev != inst->dev && + libusb_get_bus_number( instance->dev ) == bus_number && + ++index == conn_info->ConnectionIndex) + { + struct libusb_device_descriptor desc; + + if (libusb_get_device_descriptor( instance->dev, &desc )) + break; + memcpy( &conn_info->DeviceDescriptor, &desc, + sizeof(USB_DEVICE_DESCRIPTOR) ); + conn_info->ConnectionStatus = 1; + break; + } + } +#else + for (dev = inst->dev->next; dev; dev = dev->next) + if (++index == conn_info->ConnectionIndex) + { + memcpy( &conn_info->DeviceDescriptor, &dev->descriptor, + sizeof(USB_DEVICE_DESCRIPTOR) ); + conn_info->ConnectionStatus = 1; + break; + } +#endif + status = STATUS_SUCCESS; + info = sizeof(*conn_info); + break; + } + case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME: + { + USB_NODE_CONNECTION_DRIVERKEY_NAME *driver_key_name = + irp->AssociatedIrp.SystemBuffer; + WCHAR *dev_instance_idW, *bufW; + struct DeviceInstance *instance; + HDEVINFO set; + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + ULONG len, index = 0, found = 0; +#ifdef HAVE_LIBUSB_H + uint8_t bus_number = libusb_get_bus_number( inst->dev ); +#else + struct usb_device *dev; +#endif + + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < + sizeof(*driver_key_name)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } +#ifdef HAVE_LIBUSB_H + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->dev && instance->dev != inst->dev && + libusb_get_bus_number( instance->dev ) == bus_number && + ++index == driver_key_name->ConnectionIndex) + { + found = 1; + break; + } + } +#else + for (dev = inst->dev->next; dev; dev = dev->next) + if (++index == driver_key_name->ConnectionIndex) + { + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->dev == dev) + { + found = 1; + break; + } + } + break; + } +#endif + if (!found) + { + status = STATUS_INVALID_PARAMETER; + break; + } + bufW = HeapAlloc( GetProcessHeap(), 0, + 2 * MAX_DEVICE_ID_LEN * sizeof(WCHAR) ); + if (bufW == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + dev_instance_idW = bufW + MAX_DEVICE_ID_LEN; + snprintfW( dev_instance_idW, MAX_DEVICE_ID_LEN, device_idW, + instance->vid, instance->pid ); + len = strlenW(dev_instance_idW); + RtlMultiByteToUnicodeN( dev_instance_idW + len, + (MAX_DEVICE_ID_LEN - len) * sizeof(WCHAR), NULL, + instance->instance_id, strlen(instance->instance_id) + 1 ); + set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) + { + HeapFree( GetProcessHeap(), 0, bufW ); + break; + } + index = 0; + while (SetupDiEnumDeviceInfo( set, index++, &devInfo )) + { + if (!SetupDiGetDeviceInstanceIdW( set, &devInfo, bufW, + MAX_DEVICE_ID_LEN, NULL )) + break; + if (!strcmpiW( dev_instance_idW, bufW )) + { + SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_DRIVER, + NULL, NULL, 0, &len ); + driver_key_name->ActualLength = 2 * sizeof(ULONG) + len; + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < + driver_key_name->ActualLength) + { + status = STATUS_SUCCESS; + info = sizeof(*driver_key_name); + } + else if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, + SPDRP_DRIVER, NULL, (BYTE *)driver_key_name->DriverKeyName, + len, NULL )) + { + status = STATUS_SUCCESS; + info = driver_key_name->ActualLength; + } + break; + } + } + SetupDiDestroyDeviceInfoList( set ); + HeapFree( GetProcessHeap(), 0, bufW ); + break; + } + default: + FIXME( "IOCTL %08x is not implemented\n", + irpsp->Parameters.DeviceIoControl.IoControlCode ); + } + +done: + irp->IoStatus.u.Status = status; + irp->IoStatus.Information = info; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + + return status; +} + +#ifdef HAVE_LIBUSB_H + +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; + if (!inst->service) goto done; + 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: + { + struct _URB_SELECT_CONFIGURATION *request = + &urb->u.UrbSelectConfiguration; + libusb_device_handle *husb; + + TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" ); + + if (!libusb_open( inst->dev, &husb )) + { + USB_CONFIGURATION_DESCRIPTOR *conf_desc = + request->ConfigurationDescriptor; + struct libusb_config_descriptor *conf; + int ret; + + ret = libusb_set_configuration( husb, (conf_desc != NULL) ? + conf_desc->bConfigurationValue : -1 ); + if (ret < 0) + ERR( "libusb_set_configuration: %d\n", ret ); + else if (conf_desc == NULL) + status = STATUS_SUCCESS; + else if (!libusb_get_active_config_descriptor( inst->dev, &conf )) + { + USBD_INTERFACE_INFORMATION *if_info = &request->Interface; + const struct libusb_interface_descriptor *intf; + ULONG k, n; + + /* FIXME: case of num_altsetting > 1 */ + + for (n = 0; n < conf_desc->bNumInterfaces; ++n) + { + intf = &conf->interface[n].altsetting[0]; + if_info->Class = intf->bInterfaceClass; + if_info->SubClass = intf->bInterfaceSubClass; + if_info->Protocol = intf->bInterfaceProtocol; + if_info->InterfaceHandle = + (void *)(intf->bInterfaceNumber + 1); + for (k = 0; k < if_info->NumberOfPipes; ++k) + { + if_info->Pipes[k].MaximumPacketSize = + intf->endpoint[k].wMaxPacketSize; + if_info->Pipes[k].EndpointAddress = + intf->endpoint[k].bEndpointAddress; + if_info->Pipes[k].Interval = + intf->endpoint[k].bInterval; + if_info->Pipes[k].PipeType = + intf->endpoint[k].bmAttributes & 3; + if_info->Pipes[k].PipeHandle = + (void *)(intf->endpoint[k].bEndpointAddress + + ((intf->bInterfaceNumber + 1) << 8)); + } + if_info = (USBD_INTERFACE_INFORMATION *) + ((char *)if_info + if_info->Length); + } + libusb_free_config_descriptor( conf ); + status = STATUS_SUCCESS; + } + libusb_close( husb ); + } + } + break; + case URB_FUNCTION_SELECT_INTERFACE: + { + struct _URB_SELECT_INTERFACE *request = + &urb->u.UrbSelectInterface; + libusb_device_handle *husb; + + TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" ); + + if (!libusb_open( inst->dev, &husb )) + { + int ret; + + ret = libusb_claim_interface( husb, + request->Interface.InterfaceNumber ); + if (!ret) + { + ret = libusb_set_interface_alt_setting( husb, + request->Interface.InterfaceNumber, + request->Interface.AlternateSetting ); + if (!libusb_release_interface( husb, + request->Interface.InterfaceNumber ) && !ret) + status = STATUS_SUCCESS; + } + libusb_close( husb ); + } + } + break; + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + { + struct _URB_BULK_OR_INTERRUPT_TRANSFER *request = + &urb->u.UrbBulkOrInterruptTransfer; + unsigned char *buf = request->TransferBuffer; + libusb_device_handle *husb; + + TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" ); + + if (buf == NULL && request->TransferBufferMDL != NULL) + buf = request->TransferBufferMDL->MappedSystemVa; + if (!libusb_open( inst->dev, &husb )) + { + int ret, transferred; + + ret = libusb_claim_interface( husb, + ((int)request->PipeHandle >> 8) - 1 ); + if (!ret) + { + /* FIXME: add support for an interrupt transfer */ + ret = libusb_bulk_transfer( husb, + (unsigned int)request->PipeHandle, + buf, request->TransferBufferLength, + &transferred, 0 ); + if (!libusb_release_interface( husb, + ((int)request->PipeHandle >> 8) - 1 ) && !ret) + { + request->TransferBufferLength = transferred; + status = STATUS_SUCCESS; + } + } + libusb_close( husb ); + } + } + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + { + struct _URB_CONTROL_DESCRIPTOR_REQUEST *request = + &urb->u.UrbControlDescriptorRequest; + ULONG size = request->TransferBufferLength; + unsigned char *buf = request->TransferBuffer; + + TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" ); + + if (!size) + { + status = STATUS_SUCCESS; + break; + } + if (buf == NULL && request->TransferBufferMDL != NULL) + buf = request->TransferBufferMDL->MappedSystemVa; + if (buf == NULL) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + switch (request->DescriptorType) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" ); + { + struct libusb_device_descriptor desc; + + if (libusb_get_device_descriptor( inst->dev, &desc )) + break; + memcpy( buf, &desc, (size < sizeof(USB_DEVICE_DESCRIPTOR)) ? + size : sizeof(USB_DEVICE_DESCRIPTOR) ); + status = STATUS_SUCCESS; + } + break; + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" ); + { + unsigned int i, k; + struct libusb_config_descriptor *conf; + const struct libusb_interface_descriptor *intf; + const struct libusb_endpoint_descriptor *endp; + + /* FIXME: case of num_altsetting > 1 */ + + if (libusb_get_active_config_descriptor( inst->dev, &conf )) + break; + add_data( &buf, &size, conf, + sizeof(USB_CONFIGURATION_DESCRIPTOR) ); + if (size > 0 && conf->extra) + add_data( &buf, &size, conf->extra, conf->extra_length ); + for (i = 0; i < conf->bNumInterfaces; ++i) + { + intf = &conf->interface[i].altsetting[0]; + if (size > 0) + add_data( &buf, &size, intf, + sizeof(USB_INTERFACE_DESCRIPTOR) ); + if (size > 0 && intf->extra) + add_data( &buf, &size, intf->extra, intf->extra_length ); + for (k = 0; k < intf->bNumEndpoints; ++k) + { + endp = &intf->endpoint[k]; + if (size > 0) + add_data( &buf, &size, endp, + sizeof(USB_ENDPOINT_DESCRIPTOR) ); + if (size > 0 && endp->extra) + add_data( &buf, &size, endp->extra, + endp->extra_length ); + } + } + libusb_free_config_descriptor( conf ); + status = STATUS_SUCCESS; + } + break; + case USB_STRING_DESCRIPTOR_TYPE: + TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" ); + { + libusb_device_handle *husb; + int ret; + + if (!libusb_open( inst->dev, &husb )) + { + ret = libusb_get_string_descriptor( husb, request->Index, + request->LanguageId, buf, size ); + libusb_close( husb ); + if (ret < 0) break; + status = STATUS_SUCCESS; + } + } + } + } + break; + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + { + struct _URB_CONTROL_GET_STATUS_REQUEST *request = + &urb->u.UrbControlGetStatusRequest; + void *buf = request->TransferBuffer; + libusb_device_handle *husb; + int ret; + + TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" ); + + if (buf == NULL && request->TransferBufferMDL != NULL) + buf = request->TransferBufferMDL->MappedSystemVa; + if (buf == NULL || request->TransferBufferLength < sizeof(USHORT)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + if (!libusb_open( inst->dev, &husb )) + { + ret = libusb_control_transfer( husb, 1 << 7, + LIBUSB_REQUEST_GET_STATUS, 0, request->Index, buf, + sizeof(USHORT), 0 ); + libusb_close( husb ); + if (ret < 0) break; + status = STATUS_SUCCESS; + } + } + break; + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + { + libusb_device_handle *husb; + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request = + &urb->u.UrbControlVendorClassRequest; + unsigned char *req_buf = request->TransferBuffer; + ULONG size = request->TransferBufferLength; + + TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" ); + + if (req_buf == NULL && request->TransferBufferMDL != NULL) + req_buf = request->TransferBufferMDL->MappedSystemVa; + if (size && req_buf == NULL) + { + status = STATUS_INVALID_PARAMETER; + break; + } + if (!libusb_open( inst->dev, &husb )) + { + UCHAR req_type = request->RequestTypeReservedBits; + unsigned char *buf; + int ret; + + switch (urb->u.UrbHeader.Function) + { + case URB_FUNCTION_VENDOR_DEVICE: req_type |= 0x40; break; + case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break; + case URB_FUNCTION_VENDOR_ENDPOINT: req_type |= 0x42; break; + case URB_FUNCTION_CLASS_DEVICE: req_type |= 0x20; break; + case URB_FUNCTION_CLASS_INTERFACE: req_type |= 0x21; break; + case URB_FUNCTION_CLASS_ENDPOINT: req_type |= 0x22; break; + } + buf = HeapAlloc( GetProcessHeap(), 0, size ); + if (buf != NULL) + { + memcpy( buf, req_buf, size ); + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + req_type |= (1 << 7); + ret = libusb_control_transfer( husb, req_type, + request->Request, request->Value, request->Index, + buf, size, 0 ); + if (ret < 0) + ERR( "libusb_control_transfer: %d\n", ret ); + else + { + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + request->TransferBufferLength = + (ret < size) ? ret : size; + memcpy( req_buf, buf, request->TransferBufferLength ); + } + status = STATUS_SUCCESS; + } + HeapFree( GetProcessHeap(), 0, buf ); + } + libusb_close( husb ); + } + } + break; + default: + FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function ); + } + urb->u.UrbHeader.Status = status; + break; + default: + FIXME( "IOCTL %08x is not implemented\n", + irpsp->Parameters.DeviceIoControl.IoControlCode ); + } + +done: + irp->IoStatus.u.Status = status; + irp->IoStatus.Information = 0; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + + return status; +} + +#else + +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; + if (!inst->service) goto done; + 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: + { + struct _URB_SELECT_CONFIGURATION *request = + &urb->u.UrbSelectConfiguration; + usb_dev_handle *husb; + + TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" ); + + husb = usb_open( inst->dev ); + if (husb) + { + USB_CONFIGURATION_DESCRIPTOR *conf_desc = + urb->u.UrbSelectConfiguration.ConfigurationDescriptor; + int ret; + + ret = usb_set_configuration( husb, (conf_desc != NULL) ? + conf_desc->bConfigurationValue : -1 ); + if (ret < 0) + ERR( "%s\n", usb_strerror() ); + else if (conf_desc == NULL) + status = STATUS_SUCCESS; + else + { + USBD_INTERFACE_INFORMATION *if_info = &request->Interface; + struct usb_config_descriptor *conf; + struct usb_interface_descriptor *intf; + ULONG k, n; + + /* FIXME: case of num_altsetting > 1 */ + + for (n = 0; n < inst->dev->descriptor.bNumConfigurations; ++n) + if (inst->dev->config[n].bConfigurationValue == + conf_desc->bConfigurationValue) + { + conf = &inst->dev->config[n]; + break; + } + for (n = 0; n < conf_desc->bNumInterfaces; ++n) + { + intf = &conf->interface[n].altsetting[0]; + if_info->Class = intf->bInterfaceClass; + if_info->SubClass = intf->bInterfaceSubClass; + if_info->Protocol = intf->bInterfaceProtocol; + if_info->SubClass = intf->bInterfaceSubClass; + if_info->Protocol = intf->bInterfaceProtocol; + if_info->InterfaceHandle = + (void *)(intf->bInterfaceNumber + 1); + for (k = 0; k < if_info->NumberOfPipes; ++k) + { + if_info->Pipes[k].MaximumPacketSize = + intf->endpoint[k].wMaxPacketSize; + if_info->Pipes[k].EndpointAddress = + intf->endpoint[k].bEndpointAddress; + if_info->Pipes[k].Interval = + intf->endpoint[k].bInterval; + if_info->Pipes[k].PipeType = + intf->endpoint[k].bmAttributes & 3; + if_info->Pipes[k].PipeHandle = + (void *)(intf->endpoint[k].bEndpointAddress + + ((intf->bInterfaceNumber + 1) << 8)); + } + if_info = (USBD_INTERFACE_INFORMATION *) + ((char *)if_info + if_info->Length); + } + status = STATUS_SUCCESS; + } + usb_close( husb ); + } + } + break; + case URB_FUNCTION_SELECT_INTERFACE: + { + struct _URB_SELECT_INTERFACE *request = + &urb->u.UrbSelectInterface; + usb_dev_handle *husb; + + TRACE( "URB_FUNCTION_SELECT_INTERFACE\n" ); + + husb = usb_open( inst->dev ); + if (husb) + { + int ret; + + ret = usb_claim_interface( husb, + request->Interface.InterfaceNumber ); + if (!ret) + { + ret = usb_set_altinterface( husb, + request->Interface.AlternateSetting ); + if (!usb_release_interface( husb, + request->Interface.InterfaceNumber ) && !ret) + status = STATUS_SUCCESS; + } + usb_close( husb ); + } + } + break; + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + { + struct _URB_BULK_OR_INTERRUPT_TRANSFER *request = + &urb->u.UrbBulkOrInterruptTransfer; + char *buf = request->TransferBuffer; + usb_dev_handle *husb; + + TRACE( "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n" ); + + if (buf == NULL && request->TransferBufferMDL != NULL) + buf = request->TransferBufferMDL->MappedSystemVa; + husb = usb_open( inst->dev ); + if (husb) + { + int ret; + + ret = usb_claim_interface( husb, + ((int)request->PipeHandle >> 8) - 1 ); + if (!ret) + { + /* FIXME: add support for an interrupt transfer */ + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + ret = usb_bulk_read( husb, (int)request->PipeHandle & 0xff, + buf, request->TransferBufferLength, 0 ); + else + ret = usb_bulk_write( husb, (int)request->PipeHandle & 0xff, + buf, request->TransferBufferLength, 0 ); + if (!usb_release_interface( husb, + ((int)request->PipeHandle >> 8) - 1 ) && ret >= 0) + { + request->TransferBufferLength = ret; + status = STATUS_SUCCESS; + } + } + usb_close( husb ); + } + } + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + { + struct _URB_CONTROL_DESCRIPTOR_REQUEST *request = + &urb->u.UrbControlDescriptorRequest; + ULONG size = request->TransferBufferLength; + unsigned char *buf = request->TransferBuffer; + + TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" ); + + if (!size) + { + status = STATUS_SUCCESS; + break; + } + if (buf == NULL && request->TransferBufferMDL != NULL) + buf = request->TransferBufferMDL->MappedSystemVa; + if (buf == NULL) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + switch (request->DescriptorType) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" ); + memcpy( buf, &inst->dev->descriptor, + (size < sizeof(USB_DEVICE_DESCRIPTOR)) ? + size : sizeof(USB_DEVICE_DESCRIPTOR) ); + status = STATUS_SUCCESS; + break; + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" ); + { + unsigned int i, k; + struct usb_config_descriptor *conf = &inst->dev->config[0]; + struct usb_interface_descriptor *intf; + struct usb_endpoint_descriptor *endp; + + /* FIXME: case of num_altsetting > 1 */ + + add_data( &buf, &size, conf, + sizeof(USB_CONFIGURATION_DESCRIPTOR) ); + if (size > 0 && conf->extra) + add_data( &buf, &size, conf->extra, conf->extralen ); + for (i = 0; i < conf->bNumInterfaces; ++i) + { + intf = &conf->interface[i].altsetting[0]; + if (size > 0) + add_data( &buf, &size, intf, + sizeof(USB_INTERFACE_DESCRIPTOR) ); + if (size > 0 && intf->extra) + add_data( &buf, &size, intf->extra, intf->extralen ); + for (k = 0; k < intf->bNumEndpoints; ++k) + { + endp = &intf->endpoint[k]; + if (size > 0) + add_data( &buf, &size, endp, + sizeof(USB_ENDPOINT_DESCRIPTOR) ); + if (size > 0 && endp->extra) + add_data( &buf, &size, endp->extra, + endp->extralen ); + } + } + status = STATUS_SUCCESS; + } + break; + case USB_STRING_DESCRIPTOR_TYPE: + TRACE( "USB_STRING_DESCRIPTOR_TYPE\n" ); + { + usb_dev_handle *husb; + int ret; + + husb = usb_open( inst->dev ); + if (husb) + { + ret = usb_get_string( husb, request->Index, + request->LanguageId, (void *)buf, size ); + if (ret < 0) + ERR( "%s\n", usb_strerror() ); + else + status = STATUS_SUCCESS; + usb_close( husb ); + } + } + } + } + break; + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + { + struct _URB_CONTROL_GET_STATUS_REQUEST *request = + &urb->u.UrbControlGetStatusRequest; + void *buf = request->TransferBuffer; + usb_dev_handle *husb; + int ret; + + TRACE( "URB_FUNCTION_GET_STATUS_FROM_DEVICE\n" ); + + if (buf == NULL && request->TransferBufferMDL != NULL) + buf = request->TransferBufferMDL->MappedSystemVa; + if (buf == NULL || request->TransferBufferLength < sizeof(USHORT)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + husb = usb_open( inst->dev ); + if (husb) + { + ret = usb_control_msg( husb, 1 << 7, USB_REQ_GET_STATUS, 0, + request->Index, buf, sizeof(USHORT), 0 ); + if (ret < 0) + ERR( "%s\n", usb_strerror() ); + else + status = STATUS_SUCCESS; + usb_close( husb ); + } + } + break; + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + { + usb_dev_handle *husb; + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request = + &urb->u.UrbControlVendorClassRequest; + unsigned char *req_buf = request->TransferBuffer; + ULONG size = request->TransferBufferLength; + + TRACE( "URB_FUNCTION_{VENDOR,CLASS}_*\n" ); + + if (req_buf == NULL && request->TransferBufferMDL != NULL) + req_buf = request->TransferBufferMDL->MappedSystemVa; + if (size && req_buf == NULL) + { + status = STATUS_INVALID_PARAMETER; + break; + } + husb = usb_open( inst->dev ); + if (husb) + { + UCHAR req_type = request->RequestTypeReservedBits; + char *buf; + int ret; + + switch (urb->u.UrbHeader.Function) + { + case URB_FUNCTION_VENDOR_DEVICE: req_type |= 0x40; break; + case URB_FUNCTION_VENDOR_INTERFACE: req_type |= 0x41; break; + case URB_FUNCTION_VENDOR_ENDPOINT: req_type |= 0x42; break; + case URB_FUNCTION_CLASS_DEVICE: req_type |= 0x20; break; + case URB_FUNCTION_CLASS_INTERFACE: req_type |= 0x21; break; + case URB_FUNCTION_CLASS_ENDPOINT: req_type |= 0x22; break; + } + buf = HeapAlloc( GetProcessHeap(), 0, size ); + if (buf != NULL) + { + memcpy( buf, req_buf, size ); + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + req_type |= (1 << 7); + ret = usb_control_msg( husb, req_type, request->Request, + request->Value, request->Index, buf, size, 0 ); + if (ret < 0) + ERR( "%s\n", usb_strerror() ); + else + { + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + request->TransferBufferLength = + (ret < size) ? ret : size; + memcpy( req_buf, buf, request->TransferBufferLength ); + } + status = STATUS_SUCCESS; + } + HeapFree( GetProcessHeap(), 0, buf ); + } + usb_close( husb ); + } + } + break; + default: + FIXME( "unsupported URB function %x\n", urb->u.UrbHeader.Function ); + } + urb->u.UrbHeader.Status = status; + break; + default: + FIXME( "IOCTL %08x is not implemented\n", + irpsp->Parameters.DeviceIoControl.IoControlCode ); + } + +done: + irp->IoStatus.u.Status = status; + irp->IoStatus.Information = 0; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + + return status; +} + +#endif + +static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp ) +{ + static const WCHAR device_idW[] = {'U','S','B','\\', + 'V','i','d','_','%','0','4','x','&', + 'P','i','d','_','%','0','4','x',0}; + static const WCHAR root_hub_idW[] = {'U','S','B','\\', + 'R','O','O','T','_','H','U','B',0}; + + struct PdoExtension *dx; + IO_STACK_LOCATION *irpsp; + NTSTATUS status; + ULONG_PTR info = 0; + + TRACE( "%p, %p\n", device, irp ); + + dx = device->DeviceExtension; + irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation; + switch (irpsp->MinorFunction) + { + case IRP_MN_QUERY_DEVICE_RELATIONS: + /* dx->instance->service is NULL for root hubs */ + if (dx->instance->service) + { + status = irp->IoStatus.u.Status; + info = irp->IoStatus.Information; + } + else + { + FIXME( "IRP_MN_QUERY_DEVICE_RELATIONS is not implemented for root hubs\n" ); + status = STATUS_NOT_IMPLEMENTED; + } + break; + case IRP_MN_QUERY_ID: + switch (irpsp->Parameters.QueryId.IdType) + { + case BusQueryDeviceID: + { + WCHAR *device_id = ExAllocatePool( PagedPool, dx->instance->service ? + sizeof(device_idW) : sizeof(root_hub_idW) ); + + if (device_id == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + if (dx->instance->service) + snprintfW( device_id, strlenW(device_idW) + 1, device_idW, + dx->instance->vid, dx->instance->pid ); + else + strcpyW( device_id, root_hub_idW ); + status = STATUS_SUCCESS; + info = (ULONG_PTR)device_id; + break; + } + case BusQueryInstanceID: + { + char *instance_id; + ULONG len; + ULONG size; + WCHAR *instance_idW; + + instance_id = strrchr( dx->instance->instance_id, '&' ); + instance_id = instance_id ? (instance_id + 1) : dx->instance->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; + IoCompleteRequest( 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; + } + + do { + ret = StartServiceW( service, 0, NULL ); + if (!ret) + { + if (ERROR_SERVICE_ALREADY_RUNNING == GetLastError()) + ret = TRUE; + else if (ERROR_SERVICE_DATABASE_LOCKED == GetLastError()) + Sleep( 100 ); + else + break; + } + } while (!ret); + + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + + return ret; +} + +static BOOL create_pdo_name( UNICODE_STRING *pdo_name ) +{ + static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\', + 'U','S','B','P','D','O','-','%','u',0}; + + static unsigned int last_pdo_num; + WCHAR *buf = RtlAllocateHeap( GetProcessHeap(), 0, 30 * sizeof(WCHAR) ); + + if (buf == NULL) return FALSE; + snprintfW( buf, 30, usbpdoW, last_pdo_num++ ); + RtlInitUnicodeString( pdo_name, buf ); + return TRUE; +} + +static DEVICE_OBJECT *create_pdo( struct DeviceInstance *inst, DRIVER_OBJECT *hubdrv ) +{ + UNICODE_STRING pdo_name; + DEVICE_OBJECT *usbdev = NULL; + + if (!create_pdo_name( &pdo_name )) return NULL; + if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name, + 0, 0, FALSE, &usbdev ) == STATUS_SUCCESS) + { + ((struct PdoExtension *)usbdev->DeviceExtension)->instance = inst; + usbdev->Flags |= DO_BUS_ENUMERATED_DEVICE | DO_POWER_PAGABLE; + usbdev->Flags &= ~DO_DEVICE_INITIALIZING; + } + RtlFreeUnicodeString( &pdo_name ); + return usbdev; +} + +static void register_root_hub_device( DEVICE_OBJECT *dev, unsigned int instance_id ) +{ + static const WCHAR root_hub_idW[] = {'U','S','B', + '\\','R','O','O','T','_','H','U','B', + '\\','%','u',0}; + + HDEVINFO set; + SP_DEVINFO_DATA devInfo; + WCHAR *devnameW; + ULONG size; + BOOL ret; + UNICODE_STRING link; + NTSTATUS status; + + size = sizeof(root_hub_idW) + 16 * sizeof(WCHAR); + devnameW = HeapAlloc( GetProcessHeap(), 0, size ); + if (devnameW == NULL) return; + snprintfW( devnameW, size / sizeof(WCHAR), root_hub_idW, instance_id ); + + set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) goto done; + devInfo.cbSize = sizeof(SP_DEVINFO_DATA); + ret = SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB, + NULL, NULL, 0, &devInfo ); + if (ret) + { + ret = SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL ); + if (!ret) goto done; + } + else if (ERROR_DEVINST_ALREADY_EXISTS != GetLastError()) goto done; + + status = IoRegisterDeviceInterface( dev, &GUID_DEVINTERFACE_USB_HUB, + NULL, &link ); + if (status == STATUS_SUCCESS) + { + IoSetDeviceInterfaceState( &link, TRUE ); + RtlFreeUnicodeString( &link ); + } +done: + if (set != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList( set ); + HeapFree( GetProcessHeap(), 0, devnameW ); +} + +static void create_root_hub_device( USHORT vid, USHORT pid, void *dev, + DRIVER_OBJECT *hubdrv ) +{ + static unsigned int instance_id; + struct DeviceInstance *instance = NULL; + DEVICE_OBJECT *hubdev; + UNICODE_STRING pdo_name = {0, 0, NULL}; + + instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) ); + if (instance == NULL) return; + instance->instance_id = HeapAlloc( GetProcessHeap(), 0, 16 ); + if (instance->instance_id == NULL) goto fail; + instance->vid = vid; + instance->pid = pid; + snprintf( instance->instance_id, 16, "%u", instance_id ); + instance->service = NULL; + instance->dev = dev; + + if (!create_pdo_name( &pdo_name )) goto fail; + if (IoCreateDevice( hubdrv, sizeof(struct PdoExtension), &pdo_name, + 0, 0, FALSE, &hubdev ) != STATUS_SUCCESS) goto fail; + + list_add_tail( &Devices, &instance->entry ); + ((struct PdoExtension *)hubdev->DeviceExtension)->instance = instance; + hubdev->Flags |= DO_POWER_PAGABLE; + hubdev->Flags &= ~DO_DEVICE_INITIALIZING; + register_root_hub_device( hubdev, instance_id ); + ++instance_id; + return; +fail: + if (instance->instance_id) + HeapFree( GetProcessHeap(), 0, instance->instance_id ); + HeapFree( GetProcessHeap(), 0, instance ); + RtlFreeUnicodeString( &pdo_name ); + return; +} + +static BOOL enum_reg_usb_devices(void) +{ + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + char *instance_id = NULL; + struct DeviceInstance *instance, *instance2; + HDEVINFO set; + DWORD size, i = 0; + USHORT vid, pid; + char *str, *buf; + BOOL ret; + + set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) return FALSE; + + while (SetupDiEnumDeviceInfo( set, i++, &devInfo )) + { + /* get VID, PID and instance ID */ + buf = HeapAlloc( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN ); + if (buf == NULL) goto fail; + ret = SetupDiGetDeviceInstanceIdA( set, &devInfo, buf, + MAX_DEVICE_ID_LEN, NULL ); + if (!ret) goto fail; + str = strstr( buf, "VID_" ); + if (str != NULL) + { + str += 4; + vid = strtol( str, NULL, 16 ); + str = strstr( str, "PID_" ); + } + if (str == NULL) + { + HeapFree( GetProcessHeap(), 0, buf ); + continue; + } + str += 4; + pid = strtol( str, NULL, 16 ); + str = strrchr( str, '\\' ); + if (str != NULL) ++str; + if (str == NULL || *str == 0) + { + ERR( "bad instance ID\n" ); + HeapFree( GetProcessHeap(), 0, buf ); + continue; + } + instance_id = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 ); + if (instance_id == NULL) goto fail; + strcpy( instance_id, str ); + HeapFree( GetProcessHeap(), 0, buf ); + + /* get service name */ + SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE, + NULL, NULL, 0, &size ); + buf = HeapAlloc( GetProcessHeap(), 0, size ); + if (buf == NULL) goto fail; + ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE, + NULL, (BYTE *)buf, size, NULL ); + if (!ret) + { + HeapFree( GetProcessHeap(), 0, buf ); + buf = NULL; + } + + /* add DeviceInstance structure to Devices list */ + instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) ); + if (instance == NULL) goto fail; + instance->vid = vid; + instance->pid = pid; + instance->instance_id = instance_id; + instance->service = (WCHAR *)buf; + instance->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 ); + HeapFree( GetProcessHeap(), 0, instance ); + } + return FALSE; +} + +static char *new_instance_id( USHORT vid, USHORT pid ) +{ + struct DeviceInstance *instance; + char *p, *prefix = NULL; + unsigned int id = 0, n, prefix_len = 0; + char *ret; + + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (vid == instance->vid && pid == instance->pid) + { + if (prefix == NULL) + { + prefix = instance->instance_id; + p = strrchr( instance->instance_id, '&' ); + if (p == NULL) prefix_len = 0; + else prefix_len = p + 1 - prefix; + id = strtoul( prefix + prefix_len, NULL, 10 ) + 1; + } + else + { + p = strrchr( instance->instance_id, '&' ); + if (prefix_len) + { + if (p == NULL || p + 1 - instance->instance_id != prefix_len || + strncmp( instance->instance_id, prefix, prefix_len )) + continue; + } + else if (p != NULL) continue; + n = strtoul( instance->instance_id + prefix_len, NULL, 10 ) + 1; + if (n > id) id = n; + } + } + } + ret = HeapAlloc( GetProcessHeap(), 0, prefix_len + 16 ); + if (ret == NULL) return NULL; + memcpy( ret, prefix, prefix_len ); + snprintf( ret + prefix_len, prefix_len + 16, "%d", id ); + return ret; +} + +static void register_usb_device( USHORT vid, USHORT pid, void *dev ) +{ + static const WCHAR id_fmtW[] = {'U','S','B', + '\\','V','i','d','_','%','0','4','x', + '&','P','i','d','_','%','0','4','x', + '\\','%','s',0}; + + struct DeviceInstance *instance; + HDEVINFO set = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA devInfo; + WCHAR *devnameW = NULL, *instance_idW = NULL; + char *instance_id; + ULONG size; + + instance_id = new_instance_id( vid, pid ); + if (instance_id == NULL) return; + + instance = HeapAlloc( GetProcessHeap(), 0, sizeof(*instance) ); + if (instance == NULL) + { + HeapFree( GetProcessHeap(), 0, instance_id ); + goto done; + } + instance->vid = vid; + instance->pid = pid; + instance->instance_id = instance_id; + instance->service = NULL; + instance->dev = dev; + list_add_tail( &Devices, &instance->entry ); + + size = (strlen(instance_id) + 1) * sizeof(WCHAR); + instance_idW = HeapAlloc( GetProcessHeap(), 0, size ); + if (instance_idW == NULL) goto done; + RtlMultiByteToUnicodeN( instance_idW, size, NULL, + instance_id, strlen(instance_id) + 1 ); + + size = sizeof(id_fmtW) + (strlenW(instance_idW) - 2) * sizeof(WCHAR); + devnameW = HeapAlloc( GetProcessHeap(), 0, size ); + if (devnameW == NULL) goto done; + snprintfW( devnameW, size / sizeof(WCHAR), id_fmtW, vid, pid, instance_idW ); + + set = SetupDiGetClassDevsW( NULL, usbW, 0, DIGCF_ALLCLASSES ); + if (set == INVALID_HANDLE_VALUE) goto done; + devInfo.cbSize = sizeof(SP_DEVINFO_DATA); + if (SetupDiCreateDeviceInfoW( set, devnameW, &GUID_DEVCLASS_USB, + NULL, NULL, 0, &devInfo )) + SetupDiRegisterDeviceInfo( set, &devInfo, 0, NULL, NULL, NULL ); +done: + if (set != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList( set ); + if (devnameW) HeapFree( GetProcessHeap(), 0, devnameW ); + if (instance_idW) HeapFree( GetProcessHeap(), 0, instance_idW ); +} + +static void start_device_drivers( DRIVER_OBJECT *hubdrv ) +{ + struct DeviceInstance *instance; + DRIVER_OBJECT *driver; + DEVICE_OBJECT *pdo; + NTSTATUS status; + + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->service == NULL || instance->dev == NULL) continue; + if (start_service( instance->service )) + { + pdo = create_pdo( instance, hubdrv ); + if (pdo == NULL) continue; + while (!(driver = __wine_get_driver_object( + instance->service ))) + Sleep( 100 ); + status = __wine_add_device( driver, pdo ); + if (status == STATUS_SUCCESS && pdo->AttachedDevice != NULL) + __wine_start_device( pdo->AttachedDevice ); + } + } +} + +static DWORD CALLBACK enum_usb_devices( void *usbhubdrv ) +{ + static const WCHAR usbhub_started_eventW[] = {'_','_','w','i','n','e', + '_','U','s','b','h','u','b', + 'S','t','a','r','t','e','d',0}; + +#ifdef HAVE_LIBUSB_H + libusb_device **devs, *dev; + struct libusb_device_descriptor desc; + unsigned int i = 0; +#else + struct usb_device *dev; + struct usb_bus *bus; + struct usb_device_descriptor *desc; +#endif + struct DeviceInstance *instance; + HANDLE event; + BOOL new_device; + + if (!enum_reg_usb_devices()) + { + ERR( "failed to enumerate USB devices\n" ); + goto end; + } + +#ifdef HAVE_LIBUSB_H + if (libusb_init( NULL )) + { + ERR( "failed to initialize libusb\n" ); + goto end; + } + if (libusb_get_device_list( NULL, &devs ) < 0) + { + libusb_exit( NULL ); + goto end; + } + while ((dev = devs[i++])) + { + if (libusb_get_device_descriptor( dev, &desc )) + { + ERR( "failed to get USB device descriptor\n" ); + continue; + } + libusb_ref_device( dev ); + if (libusb_get_device_address( dev ) == 1) + { + create_root_hub_device( desc.idVendor, desc.idProduct, dev, usbhubdrv ); + continue; + } + new_device = TRUE; + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->dev == NULL && desc.idVendor == instance->vid && + desc.idProduct == instance->pid) + { + instance->dev = dev; + new_device = FALSE; + break; + } + } + if (new_device) + register_usb_device( desc.idVendor, desc.idProduct, dev ); + } + libusb_free_device_list( devs, 1 ); +#else + usb_init(); + usb_find_busses(); + usb_find_devices(); + + for (bus = usb_busses; bus; bus = bus->next) + for (dev = bus->devices; dev; dev = dev->next) + { + if (dev->devnum > 1) continue; + desc = &bus->devices->descriptor; + create_root_hub_device( desc->idVendor, desc->idProduct, + bus->devices, usbhubdrv ); + } + for (bus = usb_busses; bus; bus = bus->next) + for (dev = bus->devices; dev; dev = dev->next) + { + if (dev->devnum <= 1) continue; + new_device = TRUE; + LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry ) + { + if (instance->dev == NULL && + dev->descriptor.idVendor == instance->vid && + dev->descriptor.idProduct == instance->pid) + { + instance->dev = dev; + new_device = FALSE; + break; + } + } + if (new_device) + register_usb_device( dev->descriptor.idVendor, + dev->descriptor.idProduct, dev ); + } +#endif + start_device_drivers( usbhubdrv ); +end: + event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW ); + SetEvent( event ); + CloseHandle( event ); + return 0; +} + +#endif + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) +{ +#ifdef HAVE_LIBUSB + HANDLE thread; + + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = usbhub_ioctl; + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl; + driver->MajorFunction[IRP_MJ_PNP] = usbhub_dispatch_pnp; + + thread = CreateThread( NULL, 0, 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 1ea8d05..aecdf8d 100644 --- a/include/ddk/ntddk.h +++ b/include/ddk/ntddk.h @@ -107,6 +107,17 @@ typedef enum _CONFIGURATION_TYPE MaximunType } CONFIGURATION_TYPE, *PCONFIGURATION_TYPE; + +#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18 + +#define DO_VERIFY_VOLUME 0x00000002 +#define DO_DEVICE_HAS_NAME 0x00000040 +#define DO_SYSTEM_BOOT_PARTITION 0x00000100 +#define DO_LONG_TERM_REQUESTS 0x00000200 +#define DO_NEVER_LAST_DEVICE 0x00000400 +#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 + + typedef VOID (WINAPI *PDRIVER_REINITIALIZE)(PDRIVER_OBJECT,PVOID,ULONG); typedef NTSTATUS (WINAPI *PIO_QUERY_DEVICE_ROUTINE)(PVOID,PUNICODE_STRING,INTERFACE_TYPE,ULONG, PKEY_VALUE_FULL_INFORMATION*,CONFIGURATION_TYPE,ULONG,PKEY_VALUE_FULL_INFORMATION*); 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/usb100.h b/include/ddk/usb100.h index 534dca1..8a868e0 100644 --- a/include/ddk/usb100.h +++ b/include/ddk/usb100.h @@ -96,6 +96,16 @@ typedef struct _USB_COMMON_DESCRIPTOR { } USB_COMMON_DESCRIPTOR; typedef struct _USB_COMMON_DESCRIPTOR *PUSB_COMMON_DESCRIPTOR; +typedef struct _USB_HUB_DESCRIPTOR { + UCHAR bDescriptorLength; + UCHAR bDescriptorType; + UCHAR bNumberOfPorts; + USHORT wHubCharacteristics; + UCHAR bPowerOnToPowerGood; + UCHAR bHubControlCurrent; + UCHAR bRemoveAndPowerMask[64]; +} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; + #include #endif diff --git a/include/ddk/usbdrivr.h b/include/ddk/usbdrivr.h new file mode 100644 index 0000000..557cbe1 --- /dev/null +++ b/include/ddk/usbdrivr.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009 Alexander Morozov for Etersoft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __USBDRIVR_H__ +#define __USBDRIVR_H__ + +#include +#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/usbioctl.h b/include/ddk/usbioctl.h new file mode 100644 index 0000000..22dfe70 --- /dev/null +++ b/include/ddk/usbioctl.h @@ -0,0 +1,90 @@ +/* + * Copyright 2009 Alexander Morozov for Etersoft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __USBIOCTL_H__ +#define __USBIOCTL_H__ + +#include +#include + +#define IOCTL_USB_GET_NODE_INFORMATION CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#include + +typedef enum _USB_HUB_NODE { + UsbHub, + UsbMIParent +} USB_HUB_NODE; + +typedef struct _USB_HUB_INFORMATION { + USB_HUB_DESCRIPTOR HubDescriptor; + BOOLEAN HubIsBusPowered; +} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; + +typedef struct _USB_MI_PARENT_INFORMATION { + ULONG NumberOfInterfaces; +} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; + +typedef struct _USB_NODE_INFORMATION { + USB_HUB_NODE NodeType; + union { + USB_HUB_INFORMATION HubInformation; + USB_MI_PARENT_INFORMATION MiParentInformation; + } u; +} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; + +typedef struct _USB_PIPE_INFO { + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + ULONG ScheduleOffset; +} USB_PIPE_INFO, *PUSB_PIPE_INFO; + +typedef enum _USB_CONNECTION_STATUS { + NoDeviceConnected, + DeviceConnected, + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth, + DeviceHubNestedTooDeeply, + DeviceInLegacyHub +} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; + +typedef struct _USB_NODE_CONNECTION_INFORMATION { + ULONG ConnectionIndex; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + UCHAR CurrentConfigurationValue; + BOOLEAN LowSpeed; + BOOLEAN DeviceIsHub; + USHORT DeviceAddress; + ULONG NumberOfOpenPipes; + USB_CONNECTION_STATUS ConnectionStatus; + USB_PIPE_INFO PipeList[0]; +} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION; + +typedef struct _USB_NODE_CONNECTION_DRIVERKEY_NAME { + ULONG ConnectionIndex; + ULONG ActualLength; + WCHAR DriverKeyName[1]; +} USB_NODE_CONNECTION_DRIVERKEY_NAME, *PUSB_NODE_CONNECTION_DRIVERKEY_NAME; + +#include + +#endif /* __USBIOCTL_H__ */ diff --git a/include/ddk/usbiodef.h b/include/ddk/usbiodef.h new file mode 100644 index 0000000..6e36eca --- /dev/null +++ b/include/ddk/usbiodef.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009 Alexander Morozov for Etersoft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __USBIODEF_H__ +#define __USBIODEF_H__ + +#define USB_SUBMIT_URB 0 + +#define USB_GET_NODE_INFORMATION 258 +#define USB_GET_NODE_CONNECTION_INFORMATION 259 +#define USB_GET_NODE_CONNECTION_DRIVERKEY_NAME 264 + +DEFINE_GUID( GUID_DEVINTERFACE_USB_HUB, + 0xF18A0E88, 0xC30C, 0x11D0, 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 ); + +#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN + +#endif /* __USBIODEF_H__ */ diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index ccdeca3..1fa484e 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, @@ -208,6 +213,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 @@ -1014,6 +1020,60 @@ 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; + +typedef enum _IO_NOTIFICATION_EVENT_CATEGORY { + EventCategoryReserved, + EventCategoryHardwareProfileChange, + EventCategoryDeviceInterfaceChange, + EventCategoryTargetDeviceChange +} IO_NOTIFICATION_EVENT_CATEGORY; + +#define PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES 0x00000001 + +typedef struct _DEVICE_INTERFACE_CHANGE_NOTIFICATION { + USHORT Version; + USHORT Size; + GUID Event; + GUID InterfaceClassGuid; + PUNICODE_STRING SymbolicLinkName; +} DEVICE_INTERFACE_CHANGE_NOTIFICATION, *PDEVICE_INTERFACE_CHANGE_NOTIFICATION; + +typedef NTSTATUS (WINAPI *PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)(PVOID,PVOID); + NTSTATUS WINAPI ObCloseHandle(IN HANDLE handle); #define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.CurrentStackLocation) @@ -1041,6 +1101,9 @@ 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 IoCallDriver(DEVICE_OBJECT*,IRP*); +void WINAPI IoCompleteRequest(IRP*,UCHAR); 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*); @@ -1048,22 +1111,38 @@ 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); +NTSTATUS WINAPI IoRegisterDeviceInterface(PDEVICE_OBJECT,CONST GUID*,PUNICODE_STRING,PUNICODE_STRING); +NTSTATUS WINAPI IoRegisterPlugPlayNotification(IO_NOTIFICATION_EVENT_CATEGORY,ULONG,PVOID,PDRIVER_OBJECT,PDRIVER_NOTIFICATION_CALLBACK_ROUTINE,PVOID,PVOID*); +NTSTATUS WINAPI IoSetDeviceInterfaceState(PUNICODE_STRING,BOOLEAN); +NTSTATUS WINAPI IoUnregisterPlugPlayNotification(PVOID); + +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); +void WINAPI ObDereferenceObject(VOID*); NTSTATUS WINAPI ObReferenceObjectByHandle(HANDLE,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,PVOID*,POBJECT_HANDLE_INFORMATION); +NTSTATUS WINAPI ObReferenceObjectByPointer(VOID*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE); NTSTATUS WINAPI PsCreateSystemThread(PHANDLE,ULONG,POBJECT_ATTRIBUTES,HANDLE,PCLIENT_ID,PKSTART_ROUTINE,PVOID); #define PsGetCurrentProcess() IoGetCurrentProcess() diff --git a/include/ddk/wdmguid.h b/include/ddk/wdmguid.h new file mode 100644 index 0000000..f506380 --- /dev/null +++ b/include/ddk/wdmguid.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009 Alexander Morozov for Etersoft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WDMGUID_H +#define __WINE_WDMGUID_H + +DEFINE_GUID(GUID_DEVICE_INTERFACE_ARRIVAL, +0xcb3a4004L, 0x46f0, 0x11d0, 0xb0, 0x8f, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3f); + +DEFINE_GUID(GUID_DEVICE_INTERFACE_REMOVAL, +0xcb3a4005L, 0x46f0, 0x11d0, 0xb0, 0x8f, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3f); + +#endif /* __WINE_WDMGUID_H */ diff --git a/programs/services/services.c b/programs/services/services.c index 091c693..3f07fce 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -20,6 +20,8 @@ #define WIN32_LEAN_AND_MEAN +#include "config.h" + #include #include #include @@ -223,6 +225,11 @@ DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *s static void scmdatabase_autostart_services(struct scmdatabase *db) { +#ifdef HAVE_LIBUSB + static const WCHAR usbhub_started_event[] = {'_','_','w','i','n','e', + '_','U','s','b','h','u','b','S','t','a','r','t','e','d',0}; + static const WCHAR usbhub[] = {'U','s','b','h','u','b',0}; +#endif struct service_entry **services_list; unsigned int i = 0; unsigned int size = 32; @@ -260,13 +267,27 @@ static void scmdatabase_autostart_services(struct scmdatabase *db) size = i; for (i = 0; i < size; i++) { +#ifdef HAVE_LIBUSB + HANDLE event = NULL; +#endif DWORD err; const WCHAR *argv[2]; service = services_list[i]; argv[0] = service->name; argv[1] = NULL; +#ifdef HAVE_LIBUSB + if (!strcmpW(service->name, usbhub)) + event = CreateEventW(NULL, TRUE, FALSE, usbhub_started_event); +#endif err = service_start(service, 1, argv); /* FIXME: do something if the service failed to start */ +#ifdef HAVE_LIBUSB + if (event) + { + WaitForSingleObject(event, 30000); + CloseHandle(event); + } +#endif release_service(service); } 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 1dcc042..cc0ba6d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3081,6 +3081,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 */ @@ -3194,3 +3195,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 28baf76..575f44c 100644 --- a/tools/wine.inf.in +++ b/tools/wine.inf.in @@ -79,11 +79,13 @@ AddReg=\ AddService=MountMgr,0x800,MountMgrService AddService=Spooler,0,SpoolerService AddService=TermService,0,TerminalServices +AddService=Usbhub,0,UsbhubService [DefaultInstall.NT.Services] AddService=MountMgr,0x800,MountMgrService AddService=Spooler,0,SpoolerService AddService=TermService,0,TerminalServices +AddService=Usbhub,0,UsbhubService [Strings] MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions" @@ -2531,6 +2533,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] @@ -2935,6 +2938,12 @@ ServiceType=32 StartType=3 ErrorControl=1 +[UsbhubService] +ServiceBinary="%12%\usbhub.sys" +ServiceType=1 +StartType=2 +ErrorControl=1 + [Services] HKLM,"System\CurrentControlSet\Services\VxD\MSTCP",,,"" -- 1.6.3.3