[Wine-patches] [eterhack 1/4] Add libusb-1.0 support.

Alexander Morozov =?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Чт Апр 30 16:59:38 MSD 2009


---
 configure.ac                |   22 +++-
 dlls/usbhub.sys/Makefile.in |    1 +
 dlls/usbhub.sys/usbhub.c    |  271 ++++++++++++++++++++++++++++++++++++++++++-
 include/config.h.in         |    3 +
 4 files changed, 285 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index 6d4d671..45deb7c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -363,7 +363,6 @@ AC_CHECK_HEADERS(\
 	syscall.h \
 	termios.h \
 	unistd.h \
-	usb.h \
 	utime.h \
 	valgrind/memcheck.h \
 	valgrind/valgrind.h
@@ -1055,13 +1054,24 @@ WINE_NOTICE_WITH(ieee1284,[test "x$ac_cv_lib_ieee1284_ieee1284_find_ports" = "x"
 
 dnl **** Check for LIBUSB ****
 AC_SUBST(USBLIBS,"")
-if test "$ac_cv_header_usb_h" = "yes" -a "x$with_usb" != "xno"
+AC_SUBST(USBINCL,"")
+if test "x$with_usb" != "xno"
 then
-    AC_CHECK_LIB(usb, usb_init,
-        [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have the libusb library and header])
-         USBLIBS="-lusb"])
+    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 "$ac_cv_lib_usb_usb_init" != "yes"],
+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.])
 
 
diff --git a/dlls/usbhub.sys/Makefile.in b/dlls/usbhub.sys/Makefile.in
index 548fe4b..a04b8cc 100644
--- a/dlls/usbhub.sys/Makefile.in
+++ b/dlls/usbhub.sys/Makefile.in
@@ -5,6 +5,7 @@ VPATH     = @srcdir@
 MODULE    = usbhub.sys
 IMPORTS   = ntoskrnl.exe kernel32 advapi32 setupapi ntdll
 EXTRADLLFLAGS = -Wb,--subsystem,native
+EXTRAINCL = @USBINCL@
 EXTRALIBS = @USBLIBS@
 
 C_SRCS = \
diff --git a/dlls/usbhub.sys/usbhub.c b/dlls/usbhub.sys/usbhub.c
index a6f80b1..5518dff 100644
--- a/dlls/usbhub.sys/usbhub.c
+++ b/dlls/usbhub.sys/usbhub.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Alexander Morozov for Etersoft
+ * 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
@@ -21,7 +21,9 @@
 
 #include <stdarg.h>
 
-#ifdef HAVE_USB_H
+#ifdef HAVE_LIBUSB_H
+#include <libusb.h>
+#elif defined(HAVE_USB_H)
 #include <usb.h>
 #endif
 
@@ -62,7 +64,11 @@ struct DeviceInstance
     USHORT pid;
     char *instance_id;
     WCHAR *service;
+#ifdef HAVE_LIBUSB_H
+    libusb_device *dev;
+#else
     struct usb_device *dev;
+#endif
 };
 
 struct PdoExtension
@@ -70,8 +76,9 @@ struct PdoExtension
     struct DeviceInstance *instance;
 };
 
-#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
-static void add_data( char **dst, int *dst_size, void *src, int src_size )
+#ifdef HAVE_LIBUSB
+
+static void add_data( char **dst, int *dst_size, const void *src, int src_size )
 {
     int copy;
 
@@ -81,6 +88,193 @@ static void add_data( char **dst, int *dst_size, void *src, int src_size )
     *dst_size -= copy;
 }
 
+#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;
+    irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
+    urb = irpsp->Parameters.Others.Argument1;
+
+    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
+    {
+    case IOCTL_INTERNAL_USB_SUBMIT_URB:
+        switch (urb->u.UrbHeader.Function)
+        {
+        case URB_FUNCTION_SELECT_CONFIGURATION:
+            {
+                USB_CONFIGURATION_DESCRIPTOR *conf_desc =
+                        urb->u.UrbSelectConfiguration.ConfigurationDescriptor;
+                libusb_device_handle *husb;
+
+                TRACE( "URB_FUNCTION_SELECT_CONFIGURATION\n" );
+
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    int ret;
+
+                    ret = libusb_set_configuration( husb,
+                            conf_desc->bConfigurationValue );
+                    if (ret < 0)
+                        ERR( "libusb_set_configuration: %d\n", ret );
+                    else
+                        status = STATUS_SUCCESS;
+                    libusb_close( husb );
+                }
+            }
+            break;
+        case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+            {
+                struct _URB_CONTROL_DESCRIPTOR_REQUEST *request =
+                        &urb->u.UrbControlDescriptorRequest;
+
+                TRACE( "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n" );
+
+                switch (request->DescriptorType)
+                {
+                case USB_DEVICE_DESCRIPTOR_TYPE:
+                    TRACE( "USB_DEVICE_DESCRIPTOR_TYPE\n" );
+                    {
+                        struct libusb_device_descriptor desc;
+
+                        if (request->TransferBuffer == NULL)
+                            break;
+                        if (sizeof(USB_DEVICE_DESCRIPTOR) <= request->TransferBufferLength)
+                        {
+                            if (libusb_get_device_descriptor( inst->dev, &desc ))
+                                break;
+                            memcpy( request->TransferBuffer, &desc,
+                                    sizeof(USB_DEVICE_DESCRIPTOR) );
+                            status = STATUS_SUCCESS;
+                        }
+                    }
+                    break;
+                case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+                    TRACE( "USB_CONFIGURATION_DESCRIPTOR_TYPE\n" );
+                    {
+                        unsigned int i, k;
+                        char *buf = request->TransferBuffer;
+                        struct libusb_config_descriptor *conf;
+                        const struct libusb_interface_descriptor *intf;
+                        const struct libusb_endpoint_descriptor *endp;
+                        int size = request->TransferBufferLength;
+
+                        /* FIXME: case of num_altsetting > 1 */
+
+                        if (buf == NULL)
+                            break;
+                        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;
+                default:
+                    FIXME( "unsupported descriptor type %x\n",
+                            request->DescriptorType );
+                }
+            }
+            break;
+        case URB_FUNCTION_VENDOR_DEVICE:
+        case URB_FUNCTION_VENDOR_INTERFACE:
+        case URB_FUNCTION_VENDOR_ENDPOINT:
+            {
+                libusb_device_handle *husb;
+                struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *request =
+                        &urb->u.UrbControlVendorClassRequest;
+
+                TRACE( "URB_FUNCTION_VENDOR_*\n" );
+
+                if (!libusb_open( inst->dev, &husb ))
+                {
+                    UCHAR req_type = request->RequestTypeReservedBits | (2 << 5);
+                    unsigned char *buf;
+                    int ret;
+
+                    if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_INTERFACE)
+                        req_type |= 1;
+                    else if (urb->u.UrbHeader.Function == URB_FUNCTION_VENDOR_ENDPOINT)
+                        req_type |= 2;
+                    buf = HeapAlloc( GetProcessHeap(), 0,
+                            request->TransferBufferLength );
+                    if (buf != NULL)
+                    {
+                        memcpy( buf, request->TransferBuffer,
+                                request->TransferBufferLength );
+                        if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                            req_type |= (1 << 7);
+                        ret = libusb_control_transfer( husb, req_type,
+                                request->Request, request->Value, request->Index,
+                                buf, request->TransferBufferLength, 1000 );
+                        if (ret < 0)
+                            ERR( "libusb_control_transfer: %d\n", ret );
+                        else
+                        {
+                            if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+                            {
+                                request->TransferBufferLength =
+                                        (ret <= request->TransferBufferLength) ?
+                                        ret : request->TransferBufferLength;
+                                memcpy( request->TransferBuffer, buf,
+                                        request->TransferBufferLength );
+                            }
+                            status = STATUS_SUCCESS;
+                        }
+                        HeapFree( GetProcessHeap(), 0, buf );
+                    }
+                    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 );
+    }
+
+    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;
@@ -257,6 +451,8 @@ static NTSTATUS WINAPI usbhub_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     return status;
 }
 
+#endif
+
 static NTSTATUS WINAPI usbhub_dispatch_pnp( DEVICE_OBJECT *device, IRP *irp )
 {
     static const WCHAR device_idW[] = {'U','S','B','\\',
@@ -500,9 +696,15 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
                                                   '_','U','s','b','h','u','b',
                                                   'S','t','a','r','t','e','d',0};
 
-    struct DeviceInstance *instance;
+#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;
+#endif
+    struct DeviceInstance *instance;
     DEVICE_OBJECT *pdo;
     DRIVER_OBJECT *driver;
     DRIVER_OBJECT *hubdrv = usbhubdrv;
@@ -515,6 +717,61 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
         return 1;
     }
 
+#ifdef HAVE_LIBUSB_H
+    if (libusb_init( NULL ))
+    {
+        ERR( "failed to initialize libusb\n" );
+        return 1;
+    }
+    if (libusb_get_device_list( NULL, &devs ) < 0)
+    {
+        libusb_exit( NULL );
+        return 1;
+    }
+    while ((dev = devs[i++]))
+    {
+        if (libusb_get_device_descriptor( dev, &desc ))
+        {
+            ERR( "failed to get USB device descriptor\n" );
+            continue;
+        }
+        LIST_FOR_EACH_ENTRY( instance, &Devices, struct DeviceInstance, entry )
+        {
+            if (instance->dev == NULL && desc.idVendor == instance->vid &&
+                desc.idProduct == instance->pid)
+            {
+                /* HACK for grdkey.sys */
+                if (instance->vid == 0xa89 && start_service( grdkeyW ))
+                {
+                    status = IoCreateDevice( hubdrv, 0, NULL, 0, 0, FALSE, &pdo );
+                    if (status != STATUS_SUCCESS) break;
+                    while (!(driver = __wine_get_driver_object( grdkeyW )))
+                        Sleep( 100 );
+                    status = __wine_add_device( driver, pdo );
+                    if (status != STATUS_SUCCESS) break;
+                    if (pdo->AttachedDevice)
+                        __wine_start_device( pdo->AttachedDevice );
+                }
+                if (start_service( instance->service ))
+                {
+                    pdo = create_pdo( instance, hubdrv );
+                    if (pdo == NULL) break;
+                    instance->dev = dev;
+                    libusb_ref_device( dev );
+                    while (!(driver = __wine_get_driver_object(
+                            instance->service )))
+                        Sleep( 100 );
+                    status = __wine_add_device( driver, pdo );
+                    if (status != STATUS_SUCCESS) break;
+                    if (pdo->AttachedDevice)
+                        __wine_start_device( pdo->AttachedDevice );
+                }
+                break;
+            }
+        }
+    }
+    libusb_free_device_list( devs, 1 );
+#else
     usb_init();
     usb_find_busses();
     usb_find_devices();
@@ -555,17 +812,19 @@ static DWORD CALLBACK enum_usb_devices( void *usbhubdrv )
                     break;
                 }
             }
+#endif
 
     event = CreateEventW( NULL, TRUE, FALSE, usbhub_started_eventW );
     SetEvent( event );
     CloseHandle( event );
     return 0;
 }
+
 #endif
 
 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
 {
-#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+#ifdef HAVE_LIBUSB
     HANDLE thread;
 
     driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = usbhub_internal_ioctl;
diff --git a/include/config.h.in b/include/config.h.in
index 43bc531..0e32157 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -351,6 +351,9 @@
 /* Define if you have the libusb library and header */
 #undef HAVE_LIBUSB
 
+/* Define to 1 if you have the <libusb.h> header file. */
+#undef HAVE_LIBUSB_H
+
 /* Define if you have the libxml2 library */
 #undef HAVE_LIBXML2
 
-- 
1.6.1.3.GIT



Подробная информация о списке рассылки Wine-patches