diff --git a/configure.ac b/configure.ac index 142d32a..6080b0f 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,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 libusb])) AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF]), [if test "x$withval" = "xno"; then ac_cv_header_tiffio_h=no; fi]) AC_ARG_WITH(v4l, AS_HELP_STRING([--without-v4l],[do not use v4l1 (v4l support)])) @@ -1162,6 +1163,28 @@ 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-1.0 **** +AC_SUBST(LIBUSBINCL,"") +AC_SUBST(LIBUSBLIBS,"") +if test "x$with_usb" != "xno" +then + ac_save_CPPFLAGS="$CPPFLAGS" + if test "$PKG_CONFIG" != "false" + then + ac_usb_libs="`$PKG_CONFIG --libs libusb-1.0 2>/dev/null`" + ac_usb_cflags="`$PKG_CONFIG --cflags libusb-1.0 2>/dev/null`" + CPPFLAGS="$CPPFLAGS $ac_usb_cflags" + fi + AC_CHECK_HEADER(libusb.h, + [AC_CHECK_LIB(usb-1.0,libusb_init, + [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb-1.0 library and header]) + LIBUSBLIBS="$ac_usb_libs" + LIBUSBINCL="$ac_usb_cflags"],,$ac_usb_libs)]) + CPPFLAGS="$ac_save_CPPFLAGS" +fi +WINE_NOTICE_WITH(usb,[test "x$ac_cv_lib_usb_1_0_libusb_init" != "xyes"], + [libusb-1.0 ${notice_platform}development files not found, USB won't be supported.]) + dnl **** Check for libv4l1 **** if test "x$with_v4l" != "xno" then @@ -2543,6 +2566,7 @@ WINE_CONFIG_DLL(url,,[url]) WINE_CONFIG_DLL(urlmon,,[urlmon]) WINE_CONFIG_TEST(dlls/urlmon/tests) WINE_CONFIG_DLL(usbd.sys,,[usbd.sys]) +WINE_CONFIG_DLL(usbhub.sys,,[usbhub.sys]) WINE_CONFIG_DLL(user.exe16,enable_win16) WINE_CONFIG_DLL(user32,,[user32]) WINE_CONFIG_TEST(dlls/user32/tests) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 7a5af73..0f77660 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -632,14 +632,9 @@ NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK acc /*********************************************************************** - * IofCallDriver (NTOSKRNL.EXE.@) + * IoCallDriver (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 IoCallDriver( DEVICE_OBJECT *device, IRP *irp ) { PDRIVER_DISPATCH dispatch; IO_STACK_LOCATION *irpsp; @@ -650,6 +645,8 @@ NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) --irp->CurrentLocation; irpsp = --irp->Tail.Overlay.s.u2.CurrentStackLocation; dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction]; +if (dispatch == NULL) { FIXME("AVOIDING CRASH DUE TO UNIMPLEMENTED MAJOR FUNCTION 0x%X\n", irpsp->MajorFunction); return STATUS_SUCCESS; } +FIXME("calling the driver at %p, function 0x%X !!!\n", dispatch, irpsp->MajorFunction); status = dispatch( device, irp ); return status; @@ -657,6 +654,21 @@ NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp ) /*********************************************************************** + * 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 +{ + TRACE( "%p %p\n", device, irp ); + return IoCallDriver( device, irp ); +} + + +/*********************************************************************** * IoGetRelatedDeviceObject (NTOSKRNL.EXE.@) */ PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject( PFILE_OBJECT obj ) @@ -679,6 +691,20 @@ PCONFIGURATION_INFORMATION WINAPI IoGetConfigurationInformation(void) /*********************************************************************** + * IoGetDeviceProperty (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoGetDeviceProperty( PDEVICE_OBJECT DeviceObject, + int DeviceProperty, + ULONG BufferLength, + PVOID PropertyBuffer, + PULONG ResultLength ) +{ + FIXME( "%p %d %u %p %p:stub\n", DeviceObject, DeviceProperty, BufferLength, PropertyBuffer, ResultLength ); + return STATUS_NOT_IMPLEMENTED; +} + + +/*********************************************************************** * IoIsWdmVersionAvailable (NTOSKRNL.EXE.@) */ NTSTATUS WINAPI IoIsWdmVersionAvailable(UCHAR MajorVersion, UCHAR MinorVersion) @@ -757,6 +783,20 @@ NTSTATUS WINAPI IoQueryDeviceDescription(PINTERFACE_TYPE itype, PULONG bus, PCON /*********************************************************************** + * IoRegisterDeviceInterface (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT obj, const GUID *interface_class_guid, + PUNICODE_STRING reference_string, PUNICODE_STRING symlink_name ) +{ + static const WCHAR devicepath[] = {'D','E','V',0}; + FIXME( "(%p, %s, %p, %p)\n", obj, debugstr_guid(interface_class_guid), + reference_string, symlink_name ); + RtlCreateUnicodeString( symlink_name, devicepath ); + return STATUS_SUCCESS;//NOT_IMPLEMENTED; +} + + +/*********************************************************************** * IoRegisterDriverReinitialization (NTOSKRNL.EXE.@) */ void WINAPI IoRegisterDriverReinitialization( PDRIVER_OBJECT obj, PDRIVER_REINITIALIZE reinit, PVOID context ) @@ -1167,6 +1207,16 @@ LONG WINAPI KeReleaseSemaphore( PRKSEMAPHORE Semaphore, KPRIORITY Increment, /*********************************************************************** + * KeResetEvent (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeResetEvent( PRKEVENT Event ) +{ + FIXME("(%p): stub\n", Event); + return 0; +} + + +/*********************************************************************** * KeQueryTimeIncrement (NTOSKRNL.EXE.@) */ ULONG WINAPI KeQueryTimeIncrement(void) @@ -1176,6 +1226,16 @@ ULONG WINAPI KeQueryTimeIncrement(void) /*********************************************************************** + * KeSetEvent (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeSetEvent( PRKEVENT Event, KPRIORITY Increment, BOOLEAN Wait ) +{ + FIXME("(%p, %d, %d): stub\n", Event, Increment, Wait); + return 0; +} + + +/*********************************************************************** * KeSetPriorityThread (NTOSKRNL.EXE.@) */ KPRIORITY WINAPI KeSetPriorityThread( PKTHREAD Thread, KPRIORITY Priority ) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 993de77..ceb02a4 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -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 @@ -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 @@ -425,7 +425,7 @@ @ stub IoReadPartitionTableEx @ stub IoReadTransferCount @ stub IoRegisterBootDriverReinitialization -@ stub IoRegisterDeviceInterface +@ stdcall IoRegisterDeviceInterface(ptr ptr ptr ptr) @ stdcall IoRegisterDriverReinitialization(ptr ptr ptr) @ stdcall IoRegisterFileSystem(ptr) @ stub IoRegisterFsRegistrationChange @@ -597,7 +597,7 @@ @ stub KeRemoveQueue @ stub KeRemoveQueueDpc @ stub KeRemoveSystemServiceTable -@ stub KeResetEvent +@ stdcall KeResetEvent(ptr) @ stub KeRestoreFloatingPointState @ stub KeRevertToUserAffinityThread @ stub KeRundownQueue @@ -607,7 +607,7 @@ @ stub KeSetAffinityThread @ stub KeSetBasePriorityThread @ stub KeSetDmaIoCoherency -@ stub KeSetEvent +@ stdcall KeSetEvent(ptr long long) @ stub KeSetEventBoostPriority @ stub KeSetIdealProcessorThread @ stub KeSetImportanceDpc diff --git a/dlls/usbhub.sys/Makefile.in b/dlls/usbhub.sys/Makefile.in new file mode 100644 index 0000000..56f7a38 --- /dev/null +++ b/dlls/usbhub.sys/Makefile.in @@ -0,0 +1,14 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = usbhub.sys +IMPORTS = kernel32 ntoskrnl.exe ntdll advapi32 setupapi +EXTRADLLFLAGS = -Wb,--subsystem,native +EXTRAINCL = @LIBUSBINCL@ +EXTRALIBS = @LIBUSBLIBS@ + +C_SRCS = \ + usbhub.c + +@MAKE_DLL_RULES@ diff --git a/dlls/usbhub.sys/usbhub.c b/dlls/usbhub.sys/usbhub.c new file mode 100644 index 0000000..0cc8c61 --- /dev/null +++ b/dlls/usbhub.sys/usbhub.c @@ -0,0 +1,763 @@ +/* + * Copyright 2010 Damjan Jovanovic + * + * 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" + +// FIXME +#include "wine/port.h" +#include + +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "winreg.h" +#include "winuser.h" +#include "setupapi.h" +#include "cfgmgr32.h" +#include "ddk/wdm.h" +#include "ddk/usb.h" +#include "ddk/usbioctl.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +#ifdef HAVE_LIBUSB +#include + +static libusb_context *context; +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(usbhub); + +#ifdef HAVE_LIBUSB + +typedef struct { + libusb_device *device; + libusb_device_handle *handle; +} WineUsbDeviceExtension; + +static DRIVER_OBJECT *usbhub_driver; +// FIXME + DRIVER_EXTENSION driver_extension; + DRIVER_OBJECT driver_obj; + +static USBD_STATUS libusb_to_usbd_status(int ret) +{ + switch (ret) + { + case LIBUSB_SUCCESS: + return USBD_STATUS_SUCCESS; + case LIBUSB_ERROR_IO: + return USBD_STATUS_INTERNAL_HC_ERROR; + case LIBUSB_ERROR_INVALID_PARAM: + return USBD_STATUS_INVALID_PARAMETER; + case LIBUSB_ERROR_ACCESS: + return USBD_STATUS_INTERNAL_HC_ERROR; + case LIBUSB_ERROR_NO_DEVICE: + return USBD_STATUS_DEVICE_GONE; + case LIBUSB_ERROR_NOT_FOUND: + return USBD_STATUS_INTERNAL_HC_ERROR; + case LIBUSB_ERROR_BUSY: + return USBD_STATUS_ERROR_BUSY; + case LIBUSB_ERROR_TIMEOUT: + return USBD_STATUS_TIMEOUT; + case LIBUSB_ERROR_OVERFLOW: + /* http://www.cypress.com/?rID=37596 */ + return USBD_STATUS_BUFFER_OVERRUN; + case LIBUSB_ERROR_PIPE: + return USBD_STATUS_STALL_PID; + case LIBUSB_ERROR_INTERRUPTED: + return USBD_STATUS_INTERNAL_HC_ERROR; + case LIBUSB_ERROR_NO_MEM: + return USBD_STATUS_NO_MEMORY; + case LIBUSB_ERROR_NOT_SUPPORTED: + return USBD_STATUS_NOT_SUPPORTED; + } + return USBD_STATUS_INTERNAL_HC_ERROR; +} + +static NTSTATUS usb_vendor_class_control_request( URB *urb, UCHAR typeAndRecipient, WineUsbDeviceExtension *device_extension ) +{ + UCHAR requestType; + UCHAR *buffer; + int ret; + + requestType = typeAndRecipient; + if (urb->u.UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + requestType |= 0x80; + if (requestType & urb->u.UrbControlVendorClassRequest.RequestTypeReservedBits) + { + FIXME( "buggy driver wants to set reserved bits 0x%02X in USB control request, aborting I/O, please report\n", + requestType & urb->u.UrbControlVendorClassRequest.RequestTypeReservedBits); + urb->u.UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + requestType |= urb->u.UrbControlVendorClassRequest.RequestTypeReservedBits; + + buffer = urb->u.UrbControlVendorClassRequest.TransferBuffer; + if (buffer == NULL) + buffer = urb->u.UrbControlVendorClassRequest.TransferBufferMDL->MappedSystemVa; + if (buffer == NULL) + { + urb->u.UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + + ret = libusb_control_transfer( device_extension->handle, requestType, + urb->u.UrbControlVendorClassRequest.Request, + urb->u.UrbControlVendorClassRequest.Value, + urb->u.UrbControlVendorClassRequest.Index, + buffer, urb->u.UrbControlVendorClassRequest.TransferBufferLength, 0 ); + if (ret >= 0) + { + urb->u.UrbControlVendorClassRequest.TransferBufferLength = ret; + urb->u.UrbHeader.Status = USBD_STATUS_SUCCESS; + return STATUS_SUCCESS; + } + else + { + urb->u.UrbHeader.Status = libusb_to_usbd_status( ret ); + return STATUS_UNSUCCESSFUL; + } +} + +static NTSTATUS submit_urb( URB *urb, WineUsbDeviceExtension *device_extension ) +{ + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + int ret; + + switch (urb->u.UrbHeader.Function) + { + case URB_FUNCTION_SELECT_CONFIGURATION: + { + TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" ); + break; + } + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + { + unsigned char *buffer; + TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" ); + + buffer = urb->u.UrbControlDescriptorRequest.TransferBuffer; + if (buffer == NULL) + buffer = urb->u.UrbControlDescriptorRequest.TransferBufferMDL->MappedSystemVa; + if (buffer == NULL) + { + urb->u.UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER; + status = STATUS_INVALID_PARAMETER; + break; + } + + switch (urb->u.UrbControlDescriptorRequest.DescriptorType) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + { + struct libusb_device_descriptor device_descriptor; + TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" ); + ret = libusb_get_device_descriptor( device_extension->device, &device_descriptor ); + if (ret == LIBUSB_SUCCESS) + { + ULONG size = urb->u.UrbControlDescriptorRequest.TransferBufferLength; + if (size > sizeof(device_descriptor)) + size = sizeof(device_descriptor); + memcpy( buffer, &device_descriptor, size ); + urb->u.UrbHeader.Status = USBD_STATUS_SUCCESS; + status = STATUS_SUCCESS; + } + else + { + ERR( "libusb error %d getting device descriptor\n", ret ); + urb->u.UrbHeader.Status = libusb_to_usbd_status( ret ); + status = STATUS_UNSUCCESSFUL; + } + break; + } + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + { + struct libusb_config_descriptor *config_descriptor; + TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" ); + ret = libusb_get_active_config_descriptor( device_extension->device, &config_descriptor ); + if (ret == LIBUSB_SUCCESS) + { + ULONG remaining = urb->u.UrbControlDescriptorRequest.TransferBufferLength; + int i; + size_t size = sizeof(USB_CONFIGURATION_DESCRIPTOR); + if (size > remaining) + size = remaining; + memcpy( buffer, config_descriptor, size ); + buffer += size; + remaining -= size; + size = config_descriptor->extra_length; + if (size > remaining) + size = remaining; + memcpy( buffer, config_descriptor->extra, size ); + buffer += size; + remaining -= size; + for (i = 0; i < config_descriptor->bNumInterfaces; i++) + { + int j; + size = sizeof(USB_INTERFACE_DESCRIPTOR); + if (size > remaining) + size = remaining; + memcpy( buffer, &config_descriptor->interface[i].altsetting[0], size ); + buffer += size; + remaining -= size; + size = config_descriptor->interface[i].altsetting[0].extra_length; + if (size > remaining) + size = remaining; + memcpy( buffer, &config_descriptor->interface[i].altsetting[0].extra, size ); + buffer += size; + remaining -= size; + for (j = 0; j < config_descriptor->interface[i].altsetting[0].bNumEndpoints; j++) + { + size = sizeof(USB_ENDPOINT_DESCRIPTOR); + if (size > remaining) + size = remaining; + memcpy( buffer, &config_descriptor->interface[i].altsetting[0].endpoint[j], size ); + buffer += size; + remaining -= size; + size = config_descriptor->interface[i].altsetting[0].endpoint[j].extra_length; + if (size > remaining) + size = remaining; + memcpy( buffer, &config_descriptor->interface[i].altsetting[0].endpoint[j].extra, size ); + buffer += size; + remaining -= size; + } + } + urb->u.UrbHeader.Status = USBD_STATUS_SUCCESS; + status = STATUS_SUCCESS; + libusb_free_config_descriptor( config_descriptor ); + } + else + { + ERR( "libusb error %d getting configuration descriptor\n", ret ); + urb->u.UrbHeader.Status = libusb_to_usbd_status( ret ); + status = STATUS_UNSUCCESSFUL; + } + break; + } + case USB_STRING_DESCRIPTOR_TYPE: + FIXME( "USB_STRING_DESCRIPTOR_TYPE: stub\n" ); + urb->u.UrbHeader.Status = STATUS_NOT_SUPPORTED; + status = STATUS_NOT_IMPLEMENTED; + break; + default: + FIXME( "unknown USB descriptor type %d\n", urb->u.UrbControlDescriptorRequest.DescriptorType ); + urb->u.UrbHeader.Status = USBD_STATUS_NOT_SUPPORTED; + status = STATUS_NOT_IMPLEMENTED; + } + break; + } + case URB_FUNCTION_VENDOR_DEVICE: + { + TRACE( "URB_FUNCTION_VENDOR_DEVICE\n" ); + status = usb_vendor_class_control_request( urb, 0x40, device_extension ); + break; + } + default: + FIXME( "unimplemented URB function %d\n", urb->u.UrbHeader.Function ); + urb->u.UrbHeader.Status = USBD_STATUS_NOT_SUPPORTED; + status = STATUS_NOT_IMPLEMENTED; + break; + } + return status; +} + +static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) +{ + IO_STACK_LOCATION *irpsp; + URB *urb = NULL; + WineUsbDeviceExtension *deviceExtension; + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + + TRACE( "(%p, %p)\n", device, irp ); + + deviceExtension = device->DeviceExtension; + irp->IoStatus.Information = 0; + irpsp = IoGetCurrentIrpStackLocation( irp ); + + switch (irpsp->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_INTERNAL_USB_SUBMIT_URB: + urb = irpsp->Parameters.Others.Argument1; + status = submit_urb( urb, deviceExtension ); + break; + default: + FIXME( "ioctl code 0x%08X is unimplemented\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); + if (urb) + urb->u.UrbHeader.Status = USBD_STATUS_NOT_SUPPORTED; + status = STATUS_NOT_IMPLEMENTED; + } + + irp->IoStatus.u.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return status; +} + +static BOOL is_any_usb_interface_unclaimed( libusb_device *device, libusb_device_handle *handle ) +{ + struct libusb_config_descriptor *config_desc = NULL; + int i; + BOOL anyInterfaceUnclaimed = FALSE; + int ret; + + ret = libusb_get_active_config_descriptor( device, &config_desc ); + if (ret != LIBUSB_SUCCESS) + { + ERR( "could not get active configuration's descriptor\n" ); + goto done; + } + + for (i = 0; i < config_desc->bNumInterfaces; i++) + { + struct libusb_interface_descriptor interface_desc = + config_desc->interface[i].altsetting[0]; + ret = libusb_kernel_driver_active( handle, interface_desc.bInterfaceNumber ); + if (ret == 0) + { + anyInterfaceUnclaimed = TRUE; + break; + } + else if (ret == 1) + ; + else + { + ERR( "checking for active kernel driver for USB interface failed with %d\n", ret ); + goto done; + } + } + /* It's still theoretically possible a user-space driver has claimed interfaces we think are free, + * but the problem also exists between other user-space drivers, with no clear solution. + */ + +done: + libusb_free_config_descriptor( config_desc ); + return anyInterfaceUnclaimed; +} + +/* find the LDR_MODULE corresponding to the driver module */ +static LDR_MODULE *find_ldr_module( HMODULE module ) +{ + LIST_ENTRY *entry, *list = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; + + for (entry = list->Flink; entry != list; entry = entry->Flink) + { + LDR_MODULE *ldr = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList); + if (ldr->BaseAddress == module) return ldr; + if (ldr->BaseAddress > (void *)module) break; + } + return NULL; +} + +/* load the driver module file */ +static HMODULE load_driver_module( const WCHAR *name ) +{ + IMAGE_NT_HEADERS *nt; + const IMAGE_IMPORT_DESCRIPTOR *imports; + size_t page_size = getpagesize(); + int i, delta; + ULONG size; + HMODULE module = LoadLibraryW( name ); + + if (!module) return NULL; + nt = RtlImageNtHeader( module ); + + if (!(delta = (char *)module - (char *)nt->OptionalHeader.ImageBase)) return module; + + /* the loader does not apply relocations to non page-aligned binaries or executables, + * we have to do it ourselves */ + + if (nt->OptionalHeader.SectionAlignment < page_size || + !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + DWORD old; + IMAGE_BASE_RELOCATION *rel, *end; + + if ((rel = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size ))) + { + WINE_TRACE( "%s: relocating from %p to %p\n", + wine_dbgstr_w(name), (char *)module - delta, module ); + end = (IMAGE_BASE_RELOCATION *)((char *)rel + size); + while (rel < end && rel->SizeOfBlock) + { + void *page = (char *)module + rel->VirtualAddress; + VirtualProtect( page, page_size, PAGE_EXECUTE_READWRITE, &old ); + rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT), + (USHORT *)(rel + 1), delta ); + if (old != PAGE_EXECUTE_READWRITE) VirtualProtect( page, page_size, old, NULL ); + if (!rel) goto error; + } + /* make sure we don't try again */ + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + } + } + + /* make sure imports are relocated too */ + if ((imports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size ))) + { + for (i = 0; imports[i].Name && imports[i].FirstThunk; i++) + { + char *name = (char *)module + imports[i].Name; + WCHAR buffer[32], *p = buffer; + + while (p < buffer + 32) if (!(*p++ = *name++)) break; + if (p <= buffer + 32) FreeLibrary( load_driver_module( buffer ) ); + } + } + + return module; + +error: + FreeLibrary( module ); + return NULL; +} + +/* call the driver init entry point */ +static NTSTATUS init_driver( WCHAR *driver_name, HMODULE module, UNICODE_STRING *keyname ) +{ + unsigned int i; + NTSTATUS status; + const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module ); + + 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_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) ); + + 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 ); + 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 ); + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] ); + + return status; +} +/* load the .sys module for a device driver */ +static HMODULE load_driver(WCHAR *driver_name) +{ + static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0}; + static const WCHAR postfixW[] = {'.','s','y','s',0}; + static const WCHAR ntprefixW[] = {'\\','?','?','\\',0}; + static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0}; + static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y', + '\\','M','a','c','h','i','n','e', + '\\','S','y','s','t','e','m', + '\\','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}; + + UNICODE_STRING keypath; + HMODULE module; + LPWSTR path = NULL, str; + DWORD type, size; + HKEY driver_hkey; + + str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(driver_name)*sizeof(WCHAR) ); + lstrcpyW( str, servicesW ); + lstrcatW( str, driver_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 NULL; + } + RtlInitUnicodeString( &keypath, str ); + + /* read the executable path from memory */ + size = 0; + if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, NULL, &size )) + { + str = HeapAlloc( GetProcessHeap(), 0, size ); + if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, (LPBYTE)str, &size )) + { + size = ExpandEnvironmentStringsW(str,NULL,0); + path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + ExpandEnvironmentStringsW(str,path,size); + } + HeapFree( GetProcessHeap(), 0, str ); + if (!path) return NULL; + } + else + { + /* default is to use the driver name + ".sys" */ + WCHAR buffer[MAX_PATH]; + GetSystemDirectoryW(buffer, MAX_PATH); + path = HeapAlloc(GetProcessHeap(),0, + (strlenW(buffer) + strlenW(driversW) + strlenW(driver_name) + strlenW(postfixW) + 1) + *sizeof(WCHAR)); + lstrcpyW(path, buffer); + lstrcatW(path, driversW); + lstrcatW(path, driver_name); + lstrcatW(path, postfixW); + } + + /* GameGuard uses an NT-style path name */ + str = path; + if (!strncmpW( path, ntprefixW, 4 )) str += 4; + + WINE_TRACE( "loading driver %s\n", wine_dbgstr_w(str) ); + + module = load_driver_module( str ); + HeapFree( GetProcessHeap(), 0, path ); + if (!module) return NULL; + + init_driver( driver_name, module, &keypath ); + return module; +} + + +static void start_service( WCHAR *service, libusb_device *device, libusb_device_handle *handle ) +{ + HMODULE module; + module = load_driver(service); + if (module) + { + DEVICE_OBJECT *device_object; + NTSTATUS status; + + FIXME("loaded driver\n"); + status = IoCreateDevice( usbhub_driver, sizeof(WineUsbDeviceExtension), NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &device_object ); + if (status == STATUS_SUCCESS) + { + NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) = + driver_obj.DriverExtension->AddDevice; + ((WineUsbDeviceExtension*)device_object->DeviceExtension)->device = device; + ((WineUsbDeviceExtension*)device_object->DeviceExtension)->handle = handle; + FIXME("calling add device at %p\n", AddDevice); + status = AddDevice( &driver_obj, device_object ); + FIXME("add device gave 0x%X\n", status); + if (status == STATUS_SUCCESS) + { + if (driver_obj.MajorFunction[IRP_MJ_PNP] == NULL) + FIXME("MJ_PNP not supported\n"); + else + { + PIRP irp; + irp = IoAllocateIrp( device_object->StackSize, FALSE ); + if (irp) + { + IO_STACK_LOCATION *irpsp; + irpsp = IoGetNextIrpStackLocation( irp ); + irp->RequestorMode = KernelMode; + irpsp->MajorFunction = IRP_MJ_PNP; + irpsp->MinorFunction = IRP_MN_START_DEVICE; + irpsp->DeviceObject = device_object; +device_object->CurrentIrp = irp; +device_object->DriverObject = usbhub_driver; +irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + status = IoCallDriver( device_object->AttachedDevice, irp ); + FIXME("IoCallDriver gave 0x%x\n", status); + IoFreeIrp( irp ); + } + else + FIXME("IoAllocateIrp failed\n"); + } + } + } + else + ERR("IoCreateDevice failed, status 0x%X\n", status); + } + else + ERR("loading driver failed\n"); +} + +static void load_usb_driver( libusb_device *device, libusb_device_handle *handle ) +{ + static const WCHAR usbW[] = {'U','S','B',0}; + int ret; + struct libusb_device_descriptor dev_desc; + DWORD i; + BOOL found = FALSE; + HDEVINFO devices = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA devinfo; + + ret = libusb_get_device_descriptor( device, &dev_desc ); + if (ret != LIBUSB_SUCCESS) + { + ERR( "getting USB device descriptor failed, error %d\n", ret ); + goto end; + } + + /* Windows could create an enum key here, + * but we do all that from winecfg + * and only when asked */ + devices = SetupDiGetClassDevsW( NULL, usbW, NULL, DIGCF_ALLCLASSES ); + if (devices == INVALID_HANDLE_VALUE) + { + ERR( "listing USB devices failed with error %d\n", GetLastError() ); + goto end; + } + + memset( &devinfo, 0, sizeof(devinfo) ); + devinfo.cbSize = sizeof(devinfo); + for (i = 0; SetupDiEnumDeviceInfo( devices, i, &devinfo ); i++) + { + CHAR deviceId[MAX_DEVICE_ID_LEN]; + if (SetupDiGetDeviceInstanceIdA( devices, &devinfo, deviceId, MAX_DEVICE_ID_LEN, NULL )) + { +#if 0 + static const WCHAR pattern[] = { + 'U','S','B','\\','V','I','D','_','%','0','4','X','&', + 'P','I','D','_','%','0','4','X',0 + }; +#endif + int vendorId, productId; + if (sscanf( deviceId, "USB\\VID_%04X&PID_%04X", &vendorId, &productId ) == 2 && + dev_desc.idVendor == vendorId && dev_desc.idProduct == productId) + { + WCHAR *service; + DWORD size = 0; + SetupDiGetDeviceRegistryPropertyW( devices, &devinfo, SPDRP_SERVICE, + NULL, NULL, 0, &size ); + service = HeapAlloc( GetProcessHeap(), 0, size ); + if (service) + { + if (SetupDiGetDeviceRegistryPropertyW( devices, &devinfo, SPDRP_SERVICE, + NULL, (PBYTE)service, size, &size )) + { + start_service( service, device, handle ); + } + else + ERR(" error %d reading service name\n", GetLastError() ); + HeapFree( GetProcessHeap(), 0, service ); + } + } + } + else + ERR( "couldn't get device instance id, error %d\n", GetLastError() ); + } + if (!found && GetLastError() != ERROR_NO_MORE_ITEMS) + ERR( "enumerating USB devices failed with error %d\n", GetLastError() ); + +end: + if (devices != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList( devices ); +} + +static void add_usb_device( libusb_device *device ) +{ + int ret; + libusb_device_handle *handle; + + ret = libusb_open( device, &handle ); + if (ret == LIBUSB_SUCCESS) + { + if (is_any_usb_interface_unclaimed( device, handle )) + { +FIXME("found free device\n"); + load_usb_driver( device, handle ); + } + libusb_close( handle ); + } + else + ERR("could not open libusb device, error %d\n", ret); +} + +static DWORD WINAPI detect_usb_devices( LPVOID arg ) +{ + /* HAL is deprecated, + * its official replacements - devkit and udev - are 100% Linux-only (wow, progress!), + * libusb-1.0 plans to support device hotplugging from version 1.1, + * so we have to poll for now. + */ + while (1) + { + libusb_device **list; + ssize_t size; + size = libusb_get_device_list( context, &list ); + if (size >= 0) + { + int i; + for (i = 0; i < size; i++) + { + add_usb_device( list[i] ); + } + libusb_free_device_list( list, 1 ); + } + else + ERR( "libusb_get_device_list failed with error %d\n", size ); + Sleep( 1000 ); +//FIXME: +break; + + } + return 0; +} + +static VOID WINAPI usbhub_unload( DRIVER_OBJECT *driver ) +{ + TRACE( "(%p)\n", driver ); + libusb_exit( context ); +} + +#endif + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) +{ + int ret = 0; + NTSTATUS status = STATUS_SUCCESS; + + TRACE( "(%p, %s)\n", driver, debugstr_w(path->Buffer) ); + +#ifdef HAVE_LIBUSB + ret = libusb_init( &context ); + if (ret == LIBUSB_SUCCESS) + { + if (CreateThread( NULL, 0, detect_usb_devices, NULL, 0, NULL ) != NULL) + { + driver->DriverUnload = usbhub_unload; + driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl; + usbhub_driver = driver; + } + else + { + ERR( "couldn't create thread to detect USB devices, error %d\n", GetLastError() ); + status = STATUS_UNSUCCESSFUL; + } + } + else + { + ERR( "libusb_init() failed with %d\n", ret ); + status = STATUS_UNSUCCESSFUL; + } +#endif + + return status; +} diff --git a/dlls/usbhub.sys/usbhub.sys.spec b/dlls/usbhub.sys/usbhub.sys.spec new file mode 100644 index 0000000..e69de29 diff --git a/include/ddk/usb.h b/include/ddk/usb.h index af1c10d..0093478 100644 --- a/include/ddk/usb.h +++ b/include/ddk/usb.h @@ -103,6 +103,7 @@ typedef PVOID USBD_INTERFACE_HANDLE; #define USBD_STATUS_BABBLE_DETECTED ((USBD_STATUS)0xC0000012) #define USBD_STATUS_DATA_BUFFER_ERROR ((USBD_STATUS)0xC0000013) #define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030) +#define USBD_STATUS_NO_MEMORY ((USBD_STATUS)0x80000100) #define USBD_STATUS_INVALID_URB_FUNCTION ((USBD_STATUS)0x80000200) #define USBD_STATUS_INVALID_PARAMETER ((USBD_STATUS)0x80000300) #define USBD_STATUS_ERROR_BUSY ((USBD_STATUS)0x80000400) diff --git a/include/ddk/usbioctl.h b/include/ddk/usbioctl.h new file mode 100644 index 0000000..8fcce74 --- /dev/null +++ b/include/ddk/usbioctl.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) Damjan Jovanovic + * + * 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 __DDK_USBIOCTL_H__ +#define __DDK_USBIOCTL_H__ + +#include "ntddk.h" +#include "usbiodef.h" + +#define IOCTL_INTERNAL_USB_SUBMIT_URB \ + CTL_CODE(FILE_DEVICE_USB, USB_SUBMIT_URB, METHOD_NEITHER, FILE_ANY_ACCESS) + +#endif diff --git a/include/ddk/usbiodef.h b/include/ddk/usbiodef.h new file mode 100644 index 0000000..0c34cdd --- /dev/null +++ b/include/ddk/usbiodef.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) Damjan Jovanovic + * + * 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 __DDK_USBIODEF_H__ +#define __DDK_USBIODEF_H__ + +#include "ntddk.h" + +#define USB_SUBMIT_URB 0 + +#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN + +#endif diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 102dda8..89c9805 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1024,14 +1024,18 @@ NTSTATUS WINAPI ObCloseHandle(IN HANDLE handle); #ifdef NONAMELESSUNION # ifdef NONAMELESSSTRUCT # define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.s.u2.CurrentStackLocation) +# define IoGetNextIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.s.u2.CurrentStackLocation - 1) # else # define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.u2.CurrentStackLocation) +# define IoGetNextIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.u2.CurrentStackLocation - 1) # endif #else # ifdef NONAMELESSSTRUCT # define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.s.CurrentStackLocation) +# define IoGetNextIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.s.CurrentStackLocation - 1) # else # define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.CurrentStackLocation) +# define IoGetNextIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.CurrentStackLocation - 1) # endif #endif @@ -1059,6 +1063,7 @@ void WINAPI ExFreePoolWithTag(PVOID,ULONG); NTSTATUS WINAPI IoAllocateDriverObjectExtension(PDRIVER_OBJECT,PVOID,ULONG,PVOID*); PVOID WINAPI IoAllocateErrorLogEntry(PVOID,UCHAR); PIRP WINAPI IoAllocateIrp(CCHAR,BOOLEAN); +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);