summaryrefslogtreecommitdiff
path: root/libusb/os/driver
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2010-03-10 13:14:51 +0000
committerPete Batard <pbatard@gmail.com>2010-03-10 13:14:51 +0000
commitfae9c17bd2405813d44186c94367d6e66d3994e6 (patch)
tree8e795a9400182bdabb61229a3791f060af1d5335 /libusb/os/driver
parent4ee3179ae1e0adefc6c5d19c036c297856ebdef9 (diff)
downloadlibusb-fae9c17bd2405813d44186c94367d6e66d3994e6.tar.gz
libusb0.sys backend integration - part 2 (Graeme Gill)c190
Diffstat (limited to 'libusb/os/driver')
-rw-r--r--libusb/os/driver/abort_endpoint.c59
-rw-r--r--libusb/os/driver/claim_interface.c58
-rw-r--r--libusb/os/driver/clear_feature.c69
-rw-r--r--libusb/os/driver/common.rc53
-rw-r--r--libusb/os/driver/dispatch.c95
-rw-r--r--libusb/os/driver/driver_api.h165
-rw-r--r--libusb/os/driver/driver_debug.c75
-rw-r--r--libusb/os/driver/driver_debug.h30
-rw-r--r--libusb/os/driver/driver_registry.c134
-rw-r--r--libusb/os/driver/get_configuration.c58
-rw-r--r--libusb/os/driver/get_descriptor.c158
-rw-r--r--libusb/os/driver/get_interface.c67
-rw-r--r--libusb/os/driver/get_status.c77
-rw-r--r--libusb/os/driver/ioctl.c332
-rw-r--r--libusb/os/driver/libusb_driver.c462
-rw-r--r--libusb/os/driver/libusb_driver.h234
-rw-r--r--libusb/os/driver/libusb_driver_rc.rc25
-rw-r--r--libusb/os/driver/makefile1
-rw-r--r--libusb/os/driver/pnp.c216
-rw-r--r--libusb/os/driver/power.c205
-rw-r--r--libusb/os/driver/release_interface.c69
-rw-r--r--libusb/os/driver/reset_device.c46
-rw-r--r--libusb/os/driver/reset_endpoint.c59
-rw-r--r--libusb/os/driver/set_configuration.c170
-rw-r--r--libusb/os/driver/set_descriptor.c77
-rw-r--r--libusb/os/driver/set_feature.c71
-rw-r--r--libusb/os/driver/set_interface.c123
-rw-r--r--libusb/os/driver/sources33
-rw-r--r--libusb/os/driver/temp13
-rw-r--r--libusb/os/driver/transfer.c238
-rw-r--r--libusb/os/driver/usbd.def35
-rw-r--r--libusb/os/driver/usbdlib_gcc.h308
-rw-r--r--libusb/os/driver/vendor_request.c138
33 files changed, 3953 insertions, 0 deletions
diff --git a/libusb/os/driver/abort_endpoint.c b/libusb/os/driver/abort_endpoint.c
new file mode 100644
index 0000000..e8dd05a
--- /dev/null
+++ b/libusb/os/driver/abort_endpoint.c
@@ -0,0 +1,59 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS abort_endpoint(libusb_device_t *dev, int endpoint, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("abort_endpoint(): endpoint 0x%02x\n", endpoint);
+ DEBUG_MESSAGE("abort_endpoint(): timeout %d\n", timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_PIPE_REQUEST));
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("abort_endpoint(): invalid configuration 0");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if(!get_pipe_handle(dev, endpoint, &urb.UrbPipeRequest.PipeHandle))
+ {
+ DEBUG_ERROR("abort_endpoint(): getting endpoint pipe failed");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
+ urb.UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("abort_endpoint(): request failed: status: 0x%x, "
+ "urb-status: 0x%x", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/libusb/os/driver/claim_interface.c b/libusb/os/driver/claim_interface.c
new file mode 100644
index 0000000..996750b
--- /dev/null
+++ b/libusb/os/driver/claim_interface.c
@@ -0,0 +1,58 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS claim_interface(libusb_device_t *dev, int interface)
+{
+ DEBUG_MESSAGE("claim_interface(): interface %d", interface);
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("claim_interface(): device is not configured");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if(interface >= LIBUSB0_MAX_NUMBER_OF_INTERFACES)
+ {
+ DEBUG_ERROR("claim_interface(): interface number %d too high",
+ interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if(!dev->config.interfaces[interface].valid)
+ {
+ DEBUG_ERROR("claim_interface(): interface %d does not exist", interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if(dev->config.interfaces[interface].claimed)
+ {
+ DEBUG_ERROR("claim_interface(): could not claim interface %d, "
+ "interface is already claimed", interface);
+ return STATUS_DEVICE_BUSY;
+ }
+
+ dev->config.interfaces[interface].claimed = TRUE;
+
+ return STATUS_SUCCESS;
+}
diff --git a/libusb/os/driver/clear_feature.c b/libusb/os/driver/clear_feature.c
new file mode 100644
index 0000000..7dad94f
--- /dev/null
+++ b/libusb/os/driver/clear_feature.c
@@ -0,0 +1,69 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+NTSTATUS clear_feature(libusb_device_t *dev,
+ int recipient, int index, int feature, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("clear_feature(): recipient %02d", recipient);
+ DEBUG_MESSAGE("clear_feature(): index %04d", index);
+ DEBUG_MESSAGE("clear_feature(): feature %04d", feature);
+ DEBUG_MESSAGE("clear_feature(): timeout %d", timeout);
+
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
+
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_OTHER;
+ break;
+ default:
+ DEBUG_ERROR("clear_feature(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_FEATURE_REQUEST);
+ urb.UrbControlFeatureRequest.FeatureSelector = (USHORT)feature;
+ urb.UrbControlFeatureRequest.Index = (USHORT)index;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("set_feature(): clearing feature failed: status: 0x%x, "
+ "urb-status: 0x%x", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/libusb/os/driver/common.rc b/libusb/os/driver/common.rc
new file mode 100644
index 0000000..5e515f4
--- /dev/null
+++ b/libusb/os/driver/common.rc
@@ -0,0 +1,53 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <winver.h>
+
+#define RT_MANIFEST 24
+#define ID_MANIFEST 1
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION RC_VERSION
+PRODUCTVERSION RC_VERSION
+FILEFLAGSMASK 0x3FL
+FILEFLAGS 0x0L
+FILEOS VOS_NT_WINDOWS32
+FILETYPE RC_FILE_TYPE
+FILESUBTYPE RC_FILE_SUB_TYPE
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "http://libusb-win32.sourceforge.net"
+ VALUE "FileDescription", RC_PRODUCT_STR
+ VALUE "FileVersion", RC_VERSION_STR
+ VALUE "InternalName", RC_FILE_NAME_STR
+ VALUE "LegalCopyright", "@ 2002-2005 S. Meyer, <ste_meyer@web.de>"
+ VALUE "OriginalFilename",RC_FILE_NAME_STR
+ VALUE "ProductName", RC_PRODUCT_STR
+ VALUE "ProductVersion", RC_VERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
diff --git a/libusb/os/driver/dispatch.c b/libusb/os/driver/dispatch.c
new file mode 100644
index 0000000..98cd8e8
--- /dev/null
+++ b/libusb/os/driver/dispatch.c
@@ -0,0 +1,95 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+NTSTATUS DDKAPI dispatch(DEVICE_OBJECT *device_object, IRP *irp)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ switch(IoGetCurrentIrpStackLocation(irp)->MajorFunction)
+ {
+ case IRP_MJ_PNP:
+ return dispatch_pnp(dev, irp);
+
+ case IRP_MJ_POWER:
+ return dispatch_power(dev, irp);
+ }
+
+ /* since this driver may run as an upper filter we have to check whether */
+ /* the IRP is sent to this device object or to the lower one */
+ if(accept_irp(dev, irp))
+ {
+ switch(IoGetCurrentIrpStackLocation(irp)->MajorFunction)
+ {
+ case IRP_MJ_DEVICE_CONTROL:
+
+ if(dev->is_started)
+ {
+ return dispatch_ioctl(dev, irp);
+ }
+ else /* not started yet */
+ {
+ return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ case IRP_MJ_CREATE:
+
+ if(dev->is_started)
+ {
+ if(InterlockedIncrement(&dev->ref_count) == 1)
+ {
+ if(dev->power_state.DeviceState != PowerDeviceD0)
+ {
+ /* power up the device, block until the call */
+ /* completes */
+ power_set_device_state(dev, PowerDeviceD0, TRUE);
+ }
+ }
+
+ return complete_irp(irp, STATUS_SUCCESS, 0);
+ }
+ else /* not started yet */
+ {
+ return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ case IRP_MJ_CLOSE:
+
+ if(!InterlockedDecrement(&dev->ref_count))
+ {
+ /* release all interfaces when the last handle is closed */
+ release_all_interfaces(dev);
+ }
+ return complete_irp(irp, STATUS_SUCCESS, 0);
+
+ case IRP_MJ_CLEANUP:
+
+ return complete_irp(irp, STATUS_SUCCESS, 0);
+
+ default:
+ return complete_irp(irp, STATUS_NOT_SUPPORTED, 0);
+ }
+ }
+ else /* the IRP is for the lower device object */
+ {
+ return pass_irp_down(dev, irp, NULL, NULL);
+ }
+}
+
diff --git a/libusb/os/driver/driver_api.h b/libusb/os/driver/driver_api.h
new file mode 100644
index 0000000..44d9a66
--- /dev/null
+++ b/libusb/os/driver/driver_api.h
@@ -0,0 +1,165 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __DRIVER_API_H__
+#define __DRIVER_API_H__
+
+enum {
+ LIBUSB0_DEBUG_OFF,
+ LIBUSB0_DEBUG_ERR,
+ LIBUSB0_DEBUG_MSG,
+};
+
+
+/* 64k */
+#define LIBUSB0_MAX_READ_WRITE 0x10000
+
+#define LIBUSB0_MAX_NUMBER_OF_DEVICES 256
+#define LIBUSB0_MAX_NUMBER_OF_CHILDREN 32
+
+#define LIBUSB0_IOCTL_SET_CONFIGURATION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_GET_CONFIGURATION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_SET_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_GET_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_SET_FEATURE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_CLEAR_FEATURE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x806, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_GET_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_SET_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x808, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_GET_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_INTERRUPT_OR_BULK_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80A, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_INTERRUPT_OR_BULK_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80B, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_VENDOR_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80C, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_VENDOR_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80D, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_RESET_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_ABORT_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_RESET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_SET_DEBUG_LEVEL CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x812, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_ISOCHRONOUS_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x813, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_ISOCHRONOUS_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x814, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_CLAIM_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x815, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB0_IOCTL_RELEASE_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x816, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#include <pshpack1.h>
+
+
+typedef struct {
+ unsigned int timeout;
+ union {
+ struct
+ {
+ unsigned int configuration;
+ } configuration;
+ struct
+ {
+ unsigned int interface;
+ unsigned int altsetting;
+ } interface;
+ struct
+ {
+ unsigned int endpoint;
+ unsigned int packet_size;
+ } endpoint;
+ struct
+ {
+ unsigned int type;
+ unsigned int recipient;
+ unsigned int request;
+ unsigned int value;
+ unsigned int index;
+ } vendor;
+ struct
+ {
+ unsigned int recipient;
+ unsigned int feature;
+ unsigned int index;
+ } feature;
+ struct
+ {
+ unsigned int recipient;
+ unsigned int index;
+ unsigned int status;
+ } status;
+ struct
+ {
+ unsigned int type;
+ unsigned int index;
+ unsigned int language_id;
+ unsigned int recipient;
+ } descriptor;
+ struct
+ {
+ unsigned int level;
+ } debug;
+ struct
+ {
+ unsigned int major;
+ unsigned int minor;
+ unsigned int micro;
+ unsigned int nano;
+ } version;
+ };
+} libusb0_request;
+
+#include <poppack.h>
+
+#endif
diff --git a/libusb/os/driver/driver_debug.c b/libusb/os/driver/driver_debug.c
new file mode 100644
index 0000000..d10ffda
--- /dev/null
+++ b/libusb/os/driver/driver_debug.c
@@ -0,0 +1,75 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+int debug_level = LIBUSB0_DEBUG_MSG;
+
+void DEBUG_PRINT_NL()
+{
+#ifdef DBG
+ if(debug_level >= LIBUSB0_DEBUG_MSG)
+ DbgPrint(("\n"));
+#endif
+}
+
+void DEBUG_SET_LEVEL(int level)
+{
+#ifdef DBG
+ debug_level = level;
+#endif
+}
+
+void DEBUG_MESSAGE(const char *format, ...)
+{
+#ifdef DBG
+
+ char tmp[256];
+
+ if(debug_level >= LIBUSB0_DEBUG_MSG)
+ {
+ va_list args;
+ va_start(args, format);
+ _vsnprintf(tmp, sizeof(tmp) - 1, format, args);
+ va_end(args);
+
+ DbgPrint("LIBUSB-DRIVER - %s", tmp);
+ }
+#endif
+}
+
+void DEBUG_ERROR(const char *format, ...)
+{
+#ifdef DBG
+
+ char tmp[256];
+
+ if(debug_level >= LIBUSB0_DEBUG_ERR)
+ {
+ va_list args;
+ va_start(args, format);
+ _vsnprintf(tmp, sizeof(tmp) - 1, format, args);
+ va_end(args);
+
+ DbgPrint("LIBUSB-DRIVER - %s", tmp);
+ }
+#endif
+}
diff --git a/libusb/os/driver/driver_debug.h b/libusb/os/driver/driver_debug.h
new file mode 100644
index 0000000..a4f396f
--- /dev/null
+++ b/libusb/os/driver/driver_debug.h
@@ -0,0 +1,30 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __LIBUSB_DEBUG_H__
+#define __LIBUSB_DEBUG_H__
+
+
+void DEBUG_PRINT_NL();
+void DEBUG_SET_LEVEL(int level);
+void DEBUG_MESSAGE(const char *format, ...);
+void DEBUG_ERROR(const char *format, ...);
+
+
+#endif
diff --git a/libusb/os/driver/driver_registry.c b/libusb/os/driver/driver_registry.c
new file mode 100644
index 0000000..aa4b5d2
--- /dev/null
+++ b/libusb/os/driver/driver_registry.c
@@ -0,0 +1,134 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+/* missing in mingw's ddk headers */
+#ifndef PLUGPLAY_REGKEY_DEVICE
+#define PLUGPLAY_REGKEY_DEVICE 1
+#endif
+
+#define LIBUSB_REG_SURPRISE_REMOVAL_OK L"SurpriseRemovalOK"
+
+
+static bool_t reg_get_property(DEVICE_OBJECT *physical_device_object,
+ int property, char *data, int size);
+
+static bool_t reg_get_property(DEVICE_OBJECT *physical_device_object,
+ int property, char *data, int size)
+{
+ WCHAR tmp[512];
+ ULONG ret;
+ ULONG i;
+
+ if(!physical_device_object || !data || !size)
+ {
+ return FALSE;
+ }
+
+ memset(data, 0, size);
+ memset(tmp, 0, sizeof(tmp));
+
+ if(NT_SUCCESS(IoGetDeviceProperty(physical_device_object,
+ property,
+ sizeof(tmp) - 2,
+ tmp,
+ &ret)) && ret)
+ {
+ /* convert unicode string to normal character string */
+ for(i = 0; (i < ret/2) && (i < ((ULONG)size - 1)); i++)
+ {
+ data[i] = (char)tmp[i];
+ }
+
+ _strlwr(data);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+bool_t reg_get_properties(libusb_device_t *dev)
+{
+ HANDLE key = NULL;
+ NTSTATUS status;
+ UNICODE_STRING name;
+ KEY_VALUE_FULL_INFORMATION *info;
+ ULONG length;
+
+ if(!dev->physical_device_object)
+ {
+ return FALSE;
+ }
+
+ /* default settings */
+ dev->surprise_removal_ok = FALSE;
+ dev->is_filter = TRUE;
+
+ status = IoOpenDeviceRegistryKey(dev->physical_device_object,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ &key);
+ if(NT_SUCCESS(status))
+ {
+ RtlInitUnicodeString(&name, LIBUSB_REG_SURPRISE_REMOVAL_OK);
+
+ length = sizeof(KEY_VALUE_FULL_INFORMATION) + name.MaximumLength
+ + sizeof(ULONG);
+
+ info = ExAllocatePool(NonPagedPool, length);
+
+ if(info)
+ {
+ memset(info, 0, length);
+
+ status = ZwQueryValueKey(key, &name, KeyValueFullInformation,
+ info, length, &length);
+
+ if(NT_SUCCESS(status) && (info->Type == REG_DWORD))
+ {
+ ULONG val = *((ULONG *)(((char *)info) + info->DataOffset));
+
+ dev->surprise_removal_ok = val ? TRUE : FALSE;
+ dev->is_filter = FALSE;
+ }
+
+ ExFreePool(info);
+ }
+
+ ZwClose(key);
+ }
+
+ return TRUE;
+}
+
+bool_t reg_get_hardware_id(DEVICE_OBJECT *physical_device_object,
+ char *data, int size)
+{
+ if(!physical_device_object || !data || !size)
+ {
+ return FALSE;
+ }
+
+ return reg_get_property(physical_device_object, DevicePropertyHardwareID,
+ data, size);
+}
+
diff --git a/libusb/os/driver/get_configuration.c b/libusb/os/driver/get_configuration.c
new file mode 100644
index 0000000..1f4aa1e
--- /dev/null
+++ b/libusb/os/driver/get_configuration.c
@@ -0,0 +1,58 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS get_configuration(libusb_device_t *dev,
+ unsigned char *configuration, int *ret,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("get_configuration(): timeout %d", timeout);
+
+ memset(&urb, 0, sizeof(URB));
+
+ urb.UrbHeader.Function = URB_FUNCTION_GET_CONFIGURATION;
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST);
+ urb.UrbControlGetConfigurationRequest.TransferBufferLength = 1;
+ urb.UrbControlGetConfigurationRequest.TransferBuffer = configuration;
+
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("get_configuration(): getting configuration failed: "
+ "status: 0x%x, urb-status: 0x%x",
+ status, urb.UrbHeader.Status);
+ *ret = 0;
+ }
+ else
+ {
+ DEBUG_MESSAGE("get_configuration(): current configuration is: %d",
+ *configuration);
+ *ret = urb.UrbControlGetConfigurationRequest.TransferBufferLength;
+ }
+
+ return status;
+}
diff --git a/libusb/os/driver/get_descriptor.c b/libusb/os/driver/get_descriptor.c
new file mode 100644
index 0000000..ef1a5d8
--- /dev/null
+++ b/libusb/os/driver/get_descriptor.c
@@ -0,0 +1,158 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS get_descriptor(libusb_device_t *dev,
+ void *buffer, int size, int type, int recipient,
+ int index, int language_id, int *received, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("get_descriptor(): buffer size %d", size);
+ DEBUG_MESSAGE("get_descriptor(): type %04d", type);
+ DEBUG_MESSAGE("get_descriptor(): recipient %04d", recipient);
+ DEBUG_MESSAGE("get_descriptor(): index %04d", index);
+ DEBUG_MESSAGE("get_descriptor(): language id %04d", language_id);
+ DEBUG_MESSAGE("get_descriptor(): timeout %d", timeout);
+
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT;
+ break;
+ default:
+ DEBUG_ERROR("get_descriptor(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+ urb.UrbControlDescriptorRequest.TransferBufferLength = size;
+ urb.UrbControlDescriptorRequest.TransferBuffer = buffer;
+ urb.UrbControlDescriptorRequest.DescriptorType = (UCHAR)type;
+ urb.UrbControlDescriptorRequest.Index = (UCHAR)index;
+ urb.UrbControlDescriptorRequest.LanguageId = (USHORT)language_id;
+
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("get_descriptor(): getting descriptor "
+ "failed: status: 0x%x, urb-status: 0x%x",
+ status, urb.UrbHeader.Status);
+ *received = 0;
+ }
+ else
+ {
+ *received = urb.UrbControlDescriptorRequest.TransferBufferLength;
+ }
+
+ return status;
+}
+
+USB_CONFIGURATION_DESCRIPTOR *
+get_config_descriptor(libusb_device_t *dev, int value, int *size)
+{
+ NTSTATUS status;
+ USB_CONFIGURATION_DESCRIPTOR *desc = NULL;
+ USB_DEVICE_DESCRIPTOR device_descriptor;
+ int i;
+ volatile int desc_size;
+
+ status = get_descriptor(dev, &device_descriptor,
+ sizeof(USB_DEVICE_DESCRIPTOR),
+ USB_DEVICE_DESCRIPTOR_TYPE,
+ USB_RECIP_DEVICE,
+ 0, 0, size, LIBUSB0_DEFAULT_TIMEOUT);
+
+ if(!NT_SUCCESS(status) || *size != sizeof(USB_DEVICE_DESCRIPTOR))
+ {
+ DEBUG_ERROR("get_config_descriptor(): getting device descriptor failed");
+ return NULL;
+ }
+
+ if(!(desc = ExAllocatePool(NonPagedPool,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR))))
+ {
+ DEBUG_ERROR("get_config_descriptor(): memory allocation error");
+ return NULL;
+ }
+
+ for(i = 0; i < device_descriptor.bNumConfigurations; i++)
+ {
+
+ if(!NT_SUCCESS(get_descriptor(dev, desc,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR),
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ USB_RECIP_DEVICE,
+ i, 0, size, LIBUSB0_DEFAULT_TIMEOUT)))
+ {
+ DEBUG_ERROR("get_config_descriptor(): getting configuration "
+ "descriptor failed");
+ break;
+ }
+
+ if(desc->bConfigurationValue == value)
+ {
+ desc_size = desc->wTotalLength;
+ ExFreePool(desc);
+
+ if(!(desc = ExAllocatePool(NonPagedPool, desc_size)))
+ {
+ DEBUG_ERROR("get_config_descriptor(): memory allocation error");
+ break;
+ }
+
+ if(!NT_SUCCESS(get_descriptor(dev, desc, desc_size,
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ USB_RECIP_DEVICE,
+ i, 0, size, LIBUSB0_DEFAULT_TIMEOUT)))
+ {
+ DEBUG_ERROR("get_config_descriptor(): getting configuration "
+ "descriptor failed");
+ break;
+ }
+
+ return desc;
+ }
+ }
+
+ if(desc)
+ {
+ ExFreePool(desc);
+ }
+
+ return NULL;
+}
diff --git a/libusb/os/driver/get_interface.c b/libusb/os/driver/get_interface.c
new file mode 100644
index 0000000..de0baeb
--- /dev/null
+++ b/libusb/os/driver/get_interface.c
@@ -0,0 +1,67 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS get_interface(libusb_device_t *dev,
+ int interface, unsigned char *altsetting,
+ int *ret, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("get_interface(): interface %d", interface);
+ DEBUG_MESSAGE("get_interface(): timeout %d", timeout);
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("get_interface(): invalid configuration 0");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ memset(&urb, 0, sizeof(URB));
+
+ urb.UrbHeader.Function = URB_FUNCTION_GET_INTERFACE;
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST);
+ urb.UrbControlGetInterfaceRequest.TransferBufferLength = 1;
+ urb.UrbControlGetInterfaceRequest.TransferBuffer = altsetting;
+ urb.UrbControlGetInterfaceRequest.Interface = (USHORT)interface;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("get_interface(): getting interface "
+ "failed: status: 0x%x, urb-status: 0x%x",
+ status, urb.UrbHeader.Status);
+ *ret = 0;
+ }
+ else
+ {
+ *ret = urb.UrbControlGetInterfaceRequest.TransferBufferLength;
+ DEBUG_MESSAGE("get_interface(): current altsetting is %d", *altsetting);
+ }
+
+ return status;
+}
+
+
diff --git a/libusb/os/driver/get_status.c b/libusb/os/driver/get_status.c
new file mode 100644
index 0000000..a60689a
--- /dev/null
+++ b/libusb/os/driver/get_status.c
@@ -0,0 +1,77 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS get_status(libusb_device_t *dev, int recipient,
+ int index, char *status, int *ret, int timeout)
+{
+ NTSTATUS _status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("get_status(): recipient %02d", recipient);
+ DEBUG_MESSAGE("get_status(): index %04d", index);
+ DEBUG_MESSAGE("get_status(): timeout %d", timeout);
+
+ memset(&urb, 0, sizeof(URB));
+
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_OTHER;
+ break;
+ default:
+ DEBUG_ERROR("get_status(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
+ urb.UrbControlGetStatusRequest.TransferBufferLength = 2;
+ urb.UrbControlGetStatusRequest.TransferBuffer = status;
+ urb.UrbControlGetStatusRequest.Index = (USHORT)index;
+
+ _status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(_status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("get_status(): getting status failed: "
+ "status: 0x%x, urb-status: 0x%x",
+ _status, urb.UrbHeader.Status);
+ *ret = 0;
+ }
+ else
+ {
+ *ret = urb.UrbControlGetStatusRequest.TransferBufferLength;
+ }
+
+ return _status;
+}
+
diff --git a/libusb/os/driver/ioctl.c b/libusb/os/driver/ioctl.c
new file mode 100644
index 0000000..d6fdb32
--- /dev/null
+++ b/libusb/os/driver/ioctl.c
@@ -0,0 +1,332 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS dispatch_ioctl(libusb_device_t *dev, IRP *irp)
+{
+ int ret = 0;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ ULONG control_code =
+ stack_location->Parameters.DeviceIoControl.IoControlCode;
+
+ ULONG input_buffer_length
+ = stack_location->Parameters.DeviceIoControl.InputBufferLength;
+ ULONG output_buffer_length
+ = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
+ ULONG transfer_buffer_length
+ = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
+
+ libusb0_request *request = (libusb0_request *)irp->AssociatedIrp.SystemBuffer;
+ char *output_buffer = (char *)irp->AssociatedIrp.SystemBuffer;
+ char *input_buffer = (char *)irp->AssociatedIrp.SystemBuffer;
+ MDL *transfer_buffer_mdl = irp->MdlAddress;
+
+ status = remove_lock_acquire(dev);
+
+ if(!NT_SUCCESS(status))
+ {
+ status = complete_irp(irp, status, 0);
+ remove_lock_release(dev);
+ return status;
+ }
+
+ if(!request || input_buffer_length < sizeof(libusb0_request)
+ || input_buffer_length > LIBUSB0_MAX_READ_WRITE
+ || output_buffer_length > LIBUSB0_MAX_READ_WRITE
+ || transfer_buffer_length > LIBUSB0_MAX_READ_WRITE)
+ {
+ DEBUG_ERROR("dispatch_ioctl(): invalid input or output buffer\n");
+
+ status = complete_irp(irp, STATUS_INVALID_PARAMETER, 0);
+ remove_lock_release(dev);
+ return status;
+ }
+
+ DEBUG_PRINT_NL();
+
+ switch(control_code)
+ {
+ case LIBUSB0_IOCTL_SET_CONFIGURATION:
+
+ status = set_configuration(dev, request->configuration.configuration,
+ request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_GET_CONFIGURATION:
+
+ if(!output_buffer || output_buffer_length < 1)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), get_configuration: invalid output "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_configuration(dev, output_buffer, &ret, request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_SET_INTERFACE:
+
+ status = set_interface(dev, request->interface.interface,
+ request->interface.altsetting, request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_GET_INTERFACE:
+
+ if(!output_buffer || output_buffer_length < 1)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), get_interface: invalid output "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_interface(dev, request->interface.interface,
+ output_buffer, &ret, request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_SET_FEATURE:
+
+ status = set_feature(dev, request->feature.recipient,
+ request->feature.index, request->feature.feature,
+ request->timeout);
+
+ break;
+
+ case LIBUSB0_IOCTL_CLEAR_FEATURE:
+
+ status = clear_feature(dev, request->feature.recipient,
+ request->feature.index, request->feature.feature,
+ request->timeout);
+
+ break;
+
+ case LIBUSB0_IOCTL_GET_STATUS:
+
+ if(!output_buffer || output_buffer_length < 2)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), get_status: invalid output buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_status(dev, request->status.recipient,
+ request->status.index, output_buffer,
+ &ret, request->timeout);
+
+ break;
+
+ case LIBUSB0_IOCTL_SET_DESCRIPTOR:
+
+ if(input_buffer_length <= sizeof(libusb0_request))
+ {
+ DEBUG_ERROR("dispatch_ioctl(), set_descriptor: invalid input "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = set_descriptor(dev,
+ input_buffer + sizeof(libusb0_request),
+ input_buffer_length - sizeof(libusb0_request),
+ request->descriptor.type,
+ request->descriptor.recipient,
+ request->descriptor.index,
+ request->descriptor.language_id,
+ &ret, request->timeout);
+
+ break;
+
+ case LIBUSB0_IOCTL_GET_DESCRIPTOR:
+
+ if(!output_buffer || !output_buffer_length)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), get_descriptor: invalid output "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_descriptor(dev, output_buffer,
+ output_buffer_length,
+ request->descriptor.type,
+ request->descriptor.recipient,
+ request->descriptor.index,
+ request->descriptor.language_id,
+ &ret, request->timeout);
+
+ break;
+
+ case LIBUSB0_IOCTL_INTERRUPT_OR_BULK_READ:
+
+ if(!transfer_buffer_mdl)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), bulk_int_read: invalid transfer "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return transfer(dev, irp,
+ USBD_TRANSFER_DIRECTION_IN,
+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
+ request->endpoint.endpoint,
+ request->endpoint.packet_size,
+ transfer_buffer_mdl,
+ transfer_buffer_length);
+
+ case LIBUSB0_IOCTL_INTERRUPT_OR_BULK_WRITE:
+
+ /* we don't check 'transfer_buffer_mdl' here because it might be NULL */
+ /* if the DLL requests to send a zero-length packet */
+ return transfer(dev, irp,
+ USBD_TRANSFER_DIRECTION_OUT,
+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
+ request->endpoint.endpoint,
+ request->endpoint.packet_size,
+ transfer_buffer_mdl,
+ transfer_buffer_length);
+
+ case LIBUSB0_IOCTL_VENDOR_READ:
+
+ if(output_buffer_length && !output_buffer)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), vendor_read: invalid output buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = vendor_class_request(dev,
+ request->vendor.type,
+ request->vendor.recipient,
+ request->vendor.request,
+ request->vendor.value,
+ request->vendor.index,
+ output_buffer,
+ output_buffer_length,
+ USBD_TRANSFER_DIRECTION_IN,
+ &ret, request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_VENDOR_WRITE:
+
+ status =
+ vendor_class_request(dev,
+ request->vendor.type,
+ request->vendor.recipient,
+ request->vendor.request,
+ request->vendor.value,
+ request->vendor.index,
+ input_buffer_length == sizeof(libusb0_request) ?
+ NULL : input_buffer + sizeof(libusb0_request),
+ input_buffer_length - sizeof(libusb0_request),
+ USBD_TRANSFER_DIRECTION_OUT,
+ &ret, request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_RESET_ENDPOINT:
+
+ status = reset_endpoint(dev, request->endpoint.endpoint,
+ request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_ABORT_ENDPOINT:
+
+ status = abort_endpoint(dev, request->endpoint.endpoint,
+ request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_RESET_DEVICE:
+
+ status = reset_device(dev, request->timeout);
+ break;
+
+ case LIBUSB0_IOCTL_SET_DEBUG_LEVEL:
+
+ DEBUG_SET_LEVEL(request->debug.level);
+ break;
+
+ case LIBUSB0_IOCTL_GET_VERSION:
+
+ if(!request || output_buffer_length < sizeof(libusb0_request))
+ {
+ DEBUG_ERROR("dispatch_ioctl(), get_version: invalid output buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ request->version.major = VERSION_MAJOR;
+ request->version.minor = VERSION_MINOR;
+ request->version.micro = VERSION_MICRO;
+ request->version.nano = VERSION_NANO;
+
+ ret = sizeof(libusb0_request);
+ break;
+
+ case LIBUSB0_IOCTL_CLAIM_INTERFACE:
+ status = claim_interface(dev, request->interface.interface);
+ break;
+
+ case LIBUSB0_IOCTL_RELEASE_INTERFACE:
+ status = release_interface(dev, request->interface.interface);
+ break;
+
+ case LIBUSB0_IOCTL_ISOCHRONOUS_READ:
+ if(!transfer_buffer_mdl)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), isochronous_read: invalid transfer "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return transfer(dev, irp, USBD_TRANSFER_DIRECTION_IN,
+ URB_FUNCTION_ISOCH_TRANSFER, request->endpoint.endpoint,
+ request->endpoint.packet_size, transfer_buffer_mdl,
+ transfer_buffer_length);
+
+ case LIBUSB0_IOCTL_ISOCHRONOUS_WRITE:
+
+ if(!transfer_buffer_mdl)
+ {
+ DEBUG_ERROR("dispatch_ioctl(), isochronous_write: invalid transfer "
+ "buffer");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return transfer(dev, irp, USBD_TRANSFER_DIRECTION_OUT,
+ URB_FUNCTION_ISOCH_TRANSFER, request->endpoint.endpoint,
+ request->endpoint.packet_size, transfer_buffer_mdl,
+ transfer_buffer_length);
+
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ status = complete_irp(irp, status, ret);
+ remove_lock_release(dev);
+
+ return status;
+}
diff --git a/libusb/os/driver/libusb_driver.c b/libusb/os/driver/libusb_driver.c
new file mode 100644
index 0000000..712bffe
--- /dev/null
+++ b/libusb/os/driver/libusb_driver.c
@@ -0,0 +1,462 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#define __LIBUSB_DRIVER_C__
+
+#include "libusb_driver.h"
+
+extern int debug_level;
+
+static void DDKAPI unload(DRIVER_OBJECT *driver_object);
+
+static NTSTATUS DDKAPI on_usbd_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context);
+
+NTSTATUS DDKAPI DriverEntry(DRIVER_OBJECT *driver_object,
+ UNICODE_STRING *registry_path)
+{
+ int i;
+
+ DEBUG_MESSAGE("DriverEntry(): loading driver");
+
+ /* initialize global variables */
+ debug_level = LIBUSB0_DEBUG_MSG;
+
+ /* initialize the driver object's dispatch table */
+ for(i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ driver_object->MajorFunction[i] = dispatch;
+ }
+
+ driver_object->DriverExtension->AddDevice = add_device;
+ driver_object->DriverUnload = unload;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS DDKAPI add_device(DRIVER_OBJECT *driver_object,
+ DEVICE_OBJECT *physical_device_object)
+{
+ NTSTATUS status;
+ DEVICE_OBJECT *device_object = NULL;
+ libusb_device_t *dev;
+ ULONG device_type;
+
+ UNICODE_STRING nt_device_name;
+ UNICODE_STRING symbolic_link_name;
+ WCHAR tmp_name_0[128];
+ WCHAR tmp_name_1[128];
+ char id[256];
+ int i;
+
+ /* get the hardware ID from the registry */
+ if(!reg_get_hardware_id(physical_device_object, id, sizeof(id)))
+ {
+ DEBUG_ERROR("add_device(): unable to read registry");
+ return STATUS_SUCCESS;
+ }
+
+ /* only attach the (filter) driver to USB devices, skip hubs */
+ /* and interfaces of composite devices */
+ if(!strstr(id, "usb\\") || strstr(id, "hub") || strstr(id, "&mi_"))
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* retrieve the type of the lower device object */
+ device_object = IoGetAttachedDeviceReference(physical_device_object);
+
+ if(device_object)
+ {
+ device_type = device_object->DeviceType;
+ ObDereferenceObject(device_object);
+ }
+ else
+ {
+ device_type = FILE_DEVICE_UNKNOWN;
+ }
+
+ /* try to create a new device object */
+ for(i = 1; i < LIBUSB0_MAX_NUMBER_OF_DEVICES; i++)
+ {
+ /* initialize some unicode strings */
+ _snwprintf(tmp_name_0, sizeof(tmp_name_0)/sizeof(WCHAR), L"%s%04d",
+ LIBUSB0_NT_DEVICE_NAME, i);
+ _snwprintf(tmp_name_1, sizeof(tmp_name_1)/sizeof(WCHAR), L"%s%04d",
+ LIBUSB0_SYMBOLIC_LINK_NAME, i);
+
+ RtlInitUnicodeString(&nt_device_name, tmp_name_0);
+ RtlInitUnicodeString(&symbolic_link_name, tmp_name_1);
+
+ /* create the object */
+ status = IoCreateDevice(driver_object,
+ sizeof(libusb_device_t),
+ &nt_device_name, device_type, 0, FALSE,
+ &device_object);
+
+ if(NT_SUCCESS(status))
+ {
+ DEBUG_MESSAGE("add_device(): device #%d created", i);
+ break;
+ }
+
+ device_object = NULL;
+
+ /* continue until an unused device name is found */
+ }
+
+ if(!device_object)
+ {
+ DEBUG_ERROR("add_device(): creating device failed");
+ return status;
+ }
+
+ status = IoCreateSymbolicLink(&symbolic_link_name, &nt_device_name);
+
+ if(!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("add_device(): creating symbolic link failed");
+ IoDeleteDevice(device_object);
+ return status;
+ }
+
+ /* setup the "device object" */
+ dev = device_object->DeviceExtension;
+
+ memset(dev, 0, sizeof(libusb_device_t));
+
+
+ /* attach the newly created device object to the stack */
+ dev->next_stack_device =
+ IoAttachDeviceToDeviceStack(device_object, physical_device_object);
+
+ if(!dev->next_stack_device)
+ {
+ DEBUG_ERROR("add_device(): attaching to device stack failed");
+ IoDeleteSymbolicLink(&symbolic_link_name);
+ IoDeleteDevice(device_object);
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ dev->self = device_object;
+ dev->physical_device_object = physical_device_object;
+ dev->id = i;
+
+ /* set initial power states */
+ dev->power_state.DeviceState = PowerDeviceD0;
+ dev->power_state.SystemState = PowerSystemWorking;
+
+ /* get device properties from the registry */
+ reg_get_properties(dev);
+
+ if(dev->is_filter)
+ {
+ /* send all USB requests to the PDO in filter driver mode */
+ dev->target_device = dev->physical_device_object;
+
+ /* use the same flags as the underlying object */
+ device_object->Flags |= dev->next_stack_device->Flags
+ & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
+ }
+ else
+ {
+ /* send all USB requests to the lower object in device driver mode */
+ dev->target_device = dev->next_stack_device;
+
+ device_object->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
+ }
+
+ clear_pipe_info(dev);
+
+ remove_lock_initialize(dev);
+
+ device_object->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ return status;
+}
+
+
+VOID DDKAPI unload(DRIVER_OBJECT *driver_object)
+{
+ DEBUG_MESSAGE("unload(): unloading driver");
+}
+
+NTSTATUS complete_irp(IRP *irp, NTSTATUS status, ULONG info)
+{
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = info;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS call_usbd(libusb_device_t *dev, void *urb, ULONG control_code,
+ int timeout)
+{
+ KEVENT event;
+ NTSTATUS status;
+ IRP *irp;
+ IO_STACK_LOCATION *next_irp_stack;
+ LARGE_INTEGER _timeout;
+ IO_STATUS_BLOCK io_status;
+
+ if(timeout > LIBUSB0_MAX_CONTROL_TRANSFER_TIMEOUT)
+ {
+ timeout = LIBUSB0_MAX_CONTROL_TRANSFER_TIMEOUT;
+ }
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ irp = IoBuildDeviceIoControlRequest(control_code, dev->target_device,
+ NULL, 0, NULL, 0, TRUE,
+ NULL, &io_status);
+
+ if(!irp)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ next_irp_stack = IoGetNextIrpStackLocation(irp);
+ next_irp_stack->Parameters.Others.Argument1 = urb;
+ next_irp_stack->Parameters.Others.Argument2 = NULL;
+
+ IoSetCompletionRoutine(irp, on_usbd_complete, &event, TRUE, TRUE, TRUE);
+
+ status = IoCallDriver(dev->target_device, irp);
+
+ if(status == STATUS_PENDING)
+ {
+ _timeout.QuadPart = -(timeout * 10000);
+
+ if(KeWaitForSingleObject(&event, Executive, KernelMode,
+ FALSE, &_timeout) == STATUS_TIMEOUT)
+ {
+ DEBUG_ERROR("call_usbd(): request timed out");
+ IoCancelIrp(irp);
+ }
+ }
+
+ /* wait until completion routine is called */
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+
+ status = irp->IoStatus.Status;
+
+ /* complete the request */
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+
+static NTSTATUS DDKAPI on_usbd_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context)
+{
+ KeSetEvent((KEVENT *) context, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+NTSTATUS pass_irp_down(libusb_device_t *dev, IRP *irp,
+ PIO_COMPLETION_ROUTINE completion_routine,
+ void *context)
+{
+ if(completion_routine)
+ {
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ IoSetCompletionRoutine(irp, completion_routine, context,
+ TRUE, TRUE, TRUE);
+ }
+ else
+ {
+ IoSkipCurrentIrpStackLocation(irp);
+ }
+
+ return IoCallDriver(dev->next_stack_device, irp);
+}
+
+bool_t accept_irp(libusb_device_t *dev, IRP *irp)
+{
+ /* check if the IRP is sent to libusb's device object or to */
+ /* the lower one. This check is neccassary since the device object */
+ /* might be a filter */
+ if(irp->Tail.Overlay.OriginalFileObject)
+ {
+ return irp->Tail.Overlay.OriginalFileObject->DeviceObject
+ == dev->self ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
+
+bool_t get_pipe_handle(libusb_device_t *dev, int endpoint_address,
+ USBD_PIPE_HANDLE *pipe_handle)
+{
+ int i, j;
+
+ *pipe_handle = NULL;
+
+ for(i = 0; i < LIBUSB0_MAX_NUMBER_OF_INTERFACES; i++)
+ {
+ if(dev->config.interfaces[i].valid)
+ {
+ for(j = 0; j < LIBUSB0_MAX_NUMBER_OF_ENDPOINTS; j++)
+ {
+ if(dev->config.interfaces[i].endpoints[j].address
+ == endpoint_address)
+ {
+ *pipe_handle = dev->config.interfaces[i].endpoints[j].handle;
+
+ return !*pipe_handle ? FALSE : TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void clear_pipe_info(libusb_device_t *dev)
+{
+ memset(dev->config.interfaces, 0 , sizeof(dev->config.interfaces));
+}
+
+bool_t update_pipe_info(libusb_device_t *dev,
+ USBD_INTERFACE_INFORMATION *interface_info)
+{
+ int i;
+ int number;
+
+ if(!interface_info)
+ {
+ return FALSE;
+ }
+
+ number = interface_info->InterfaceNumber;
+
+ if(interface_info->InterfaceNumber >= LIBUSB0_MAX_NUMBER_OF_INTERFACES)
+ {
+ return FALSE;
+ }
+
+ DEBUG_MESSAGE("update_pipe_info(): interface %d", number);
+
+ dev->config.interfaces[number].valid = TRUE;
+
+ for(i = 0; i < LIBUSB0_MAX_NUMBER_OF_ENDPOINTS; i++)
+ {
+ dev->config.interfaces[number].endpoints[i].address = 0;
+ dev->config.interfaces[number].endpoints[i].handle = NULL;
+ }
+
+ if(interface_info)
+ {
+ for(i = 0; i < (int)interface_info->NumberOfPipes
+ && i < LIBUSB0_MAX_NUMBER_OF_ENDPOINTS; i++)
+ {
+ DEBUG_MESSAGE("update_pipe_info(): endpoint address 0x%02x",
+ interface_info->Pipes[i].EndpointAddress);
+
+ dev->config.interfaces[number].endpoints[i].handle
+ = interface_info->Pipes[i].PipeHandle;
+ dev->config.interfaces[number].endpoints[i].address =
+ interface_info->Pipes[i].EndpointAddress;
+ }
+ }
+
+ return TRUE;
+}
+
+
+void remove_lock_initialize(libusb_device_t *dev)
+{
+ KeInitializeEvent(&dev->remove_lock.event, NotificationEvent, FALSE);
+ dev->remove_lock.usage_count = 1;
+ dev->remove_lock.remove_pending = FALSE;
+}
+
+
+NTSTATUS remove_lock_acquire(libusb_device_t *dev)
+{
+ InterlockedIncrement(&dev->remove_lock.usage_count);
+
+ if(dev->remove_lock.remove_pending)
+ {
+ if(InterlockedDecrement(&dev->remove_lock.usage_count) == 0)
+ {
+ KeSetEvent(&dev->remove_lock.event, 0, FALSE);
+ }
+ return STATUS_DELETE_PENDING;
+ }
+ return STATUS_SUCCESS;
+}
+
+
+void remove_lock_release(libusb_device_t *dev)
+{
+ if(InterlockedDecrement(&dev->remove_lock.usage_count) == 0)
+ {
+ KeSetEvent(&dev->remove_lock.event, 0, FALSE);
+ }
+}
+
+
+void remove_lock_release_and_wait(libusb_device_t *dev)
+{
+ dev->remove_lock.remove_pending = TRUE;
+ remove_lock_release(dev);
+ remove_lock_release(dev);
+ KeWaitForSingleObject(&dev->remove_lock.event, Executive, KernelMode,
+ FALSE, NULL);
+}
+
+
+USB_INTERFACE_DESCRIPTOR *
+find_interface_desc(USB_CONFIGURATION_DESCRIPTOR *config_desc,
+ unsigned int size, int interface_number, int altsetting)
+{
+ usb_descriptor_header_t *desc = (usb_descriptor_header_t *)config_desc;
+ char *p = (char *)desc;
+ USB_INTERFACE_DESCRIPTOR *if_desc = NULL;
+
+ if(!config_desc || (size < config_desc->wTotalLength))
+ return NULL;
+
+ while(size && desc->length <= size)
+ {
+ if(desc->type == USB_INTERFACE_DESCRIPTOR_TYPE)
+ {
+ if_desc = (USB_INTERFACE_DESCRIPTOR *)desc;
+
+ if((if_desc->bInterfaceNumber == (UCHAR)interface_number)
+ && (if_desc->bAlternateSetting == (UCHAR)altsetting))
+ {
+ return if_desc;
+ }
+ }
+
+ size -= desc->length;
+ p += desc->length;
+ desc = (usb_descriptor_header_t *)p;
+ }
+
+ return NULL;
+}
+
diff --git a/libusb/os/driver/libusb_driver.h b/libusb/os/driver/libusb_driver.h
new file mode 100644
index 0000000..7c5af5b
--- /dev/null
+++ b/libusb/os/driver/libusb_driver.h
@@ -0,0 +1,234 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __LIBUSB_DRIVER_H__
+#define __LIBUSB_DRIVER_H__
+
+#ifdef __GNUC__
+#include <ddk/usb100.h>
+#include <ddk/usbdi.h>
+#include <ddk/winddk.h>
+#include "usbdlib_gcc.h"
+#else
+#include <wdm.h>
+#include "usbdi.h"
+#include "usbdlib.h"
+#endif
+
+#include <wchar.h>
+#include <initguid.h>
+
+#undef interface
+
+#include "driver_debug.h"
+#include "driver_api.h"
+
+/* some missing defines */
+#ifdef __GNUC__
+
+#define USBD_TRANSFER_DIRECTION_OUT 0
+#define USBD_TRANSFER_DIRECTION_BIT 0
+#define USBD_TRANSFER_DIRECTION_IN (1 << USBD_TRANSFER_DIRECTION_BIT)
+#define USBD_SHORT_TRANSFER_OK_BIT 1
+#define USBD_SHORT_TRANSFER_OK (1 << USBD_SHORT_TRANSFER_OK_BIT)
+#define USBD_START_ISO_TRANSFER_ASAP_BIT 2
+#define USBD_START_ISO_TRANSFER_ASAP (1 << USBD_START_ISO_TRANSFER_ASAP_BIT)
+
+#endif
+
+
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+#define USB_TYPE_STANDARD 0x00
+#define USB_TYPE_CLASS 0x01
+#define USB_TYPE_VENDOR 0x02
+
+
+#define LIBUSB0_NT_DEVICE_NAME L"\\Device\\libusb0"
+#define LIBUSB0_SYMBOLIC_LINK_NAME L"\\DosDevices\\libusb0-"
+
+#define LIBUSB0_MAX_NUMBER_OF_ENDPOINTS 32
+#define LIBUSB0_MAX_NUMBER_OF_INTERFACES 32
+
+
+#define LIBUSB0_DEFAULT_TIMEOUT 5000
+#define LIBUSB0_MAX_CONTROL_TRANSFER_TIMEOUT 240000
+
+
+#ifndef __GNUC__
+#define DDKAPI
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!(FALSE))
+#endif
+
+typedef int bool_t;
+
+#include <pshpack1.h>
+
+typedef struct
+{
+ unsigned char length;
+ unsigned char type;
+} usb_descriptor_header_t;
+
+#include <poppack.h>
+
+
+typedef struct
+{
+ long usage_count;
+ int remove_pending;
+ KEVENT event;
+} libusb_remove_lock_t;
+
+typedef struct
+{
+ int address;
+ USBD_PIPE_HANDLE handle;
+} libusb_endpoint_t;
+
+typedef struct
+{
+ int valid;
+ int claimed;
+ libusb_endpoint_t endpoints[LIBUSB0_MAX_NUMBER_OF_ENDPOINTS];
+} libusb_interface_t;
+
+
+typedef struct
+{
+ DEVICE_OBJECT *self;
+ DEVICE_OBJECT *physical_device_object;
+ DEVICE_OBJECT *next_stack_device;
+ DEVICE_OBJECT *target_device;
+ libusb_remove_lock_t remove_lock;
+ LONG ref_count;
+ bool_t is_filter;
+ bool_t is_started;
+ bool_t surprise_removal_ok;
+ int id;
+ struct {
+ USBD_CONFIGURATION_HANDLE handle;
+ int value;
+ libusb_interface_t interfaces[LIBUSB0_MAX_NUMBER_OF_INTERFACES];
+ } config;
+ POWER_STATE power_state;
+ DEVICE_POWER_STATE device_power_states[PowerSystemMaximum];
+} libusb_device_t;
+
+
+
+NTSTATUS DDKAPI add_device(DRIVER_OBJECT *driver_object,
+ DEVICE_OBJECT *physical_device_object);
+
+NTSTATUS DDKAPI dispatch(DEVICE_OBJECT *device_object, IRP *irp);
+NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp);
+NTSTATUS dispatch_power(libusb_device_t *dev, IRP *irp);
+NTSTATUS dispatch_ioctl(libusb_device_t *dev, IRP *irp);
+
+NTSTATUS complete_irp(IRP *irp, NTSTATUS status, ULONG info);
+
+NTSTATUS call_usbd(libusb_device_t *dev, void *urb,
+ ULONG control_code, int timeout);
+NTSTATUS pass_irp_down(libusb_device_t *dev, IRP *irp,
+ PIO_COMPLETION_ROUTINE completion_routine,
+ void *context);
+
+bool_t accept_irp(libusb_device_t *dev, IRP *irp);
+
+bool_t get_pipe_handle(libusb_device_t *dev, int endpoint_address,
+ USBD_PIPE_HANDLE *pipe_handle);
+void clear_pipe_info(libusb_device_t *dev);
+bool_t update_pipe_info(libusb_device_t *dev,
+ USBD_INTERFACE_INFORMATION *interface_info);
+
+void remove_lock_initialize(libusb_device_t *dev);
+NTSTATUS remove_lock_acquire(libusb_device_t *dev);
+void remove_lock_release(libusb_device_t *dev);
+void remove_lock_release_and_wait(libusb_device_t *dev);
+
+NTSTATUS set_configuration(libusb_device_t *dev,
+ int configuration, int timeout);
+NTSTATUS get_configuration(libusb_device_t *dev,
+ unsigned char *configuration, int *ret,
+ int timeout);
+NTSTATUS set_interface(libusb_device_t *dev,
+ int interface, int altsetting, int timeout);
+NTSTATUS get_interface(libusb_device_t *dev,
+ int interface, unsigned char *altsetting,
+ int *ret, int timeout);
+NTSTATUS set_feature(libusb_device_t *dev,
+ int recipient, int index, int feature, int timeout);
+NTSTATUS clear_feature(libusb_device_t *dev,
+ int recipient, int index, int feature, int timeout);
+NTSTATUS get_status(libusb_device_t *dev, int recipient,
+ int index, char *status, int *ret, int timeout);
+NTSTATUS set_descriptor(libusb_device_t *dev,
+ void *buffer, int size,
+ int type, int recipient, int index, int language_id,
+ int *sent, int timeout);
+NTSTATUS get_descriptor(libusb_device_t *dev, void *buffer, int size,
+ int type, int recipient, int index, int language_id,
+ int *received, int timeout);
+USB_CONFIGURATION_DESCRIPTOR *
+get_config_descriptor(libusb_device_t *dev, int value, int *size);
+
+NTSTATUS transfer(libusb_device_t *dev, IRP *irp,
+ int direction, int urb_function, int endpoint,
+ int packet_size, MDL *buffer, int size);
+
+NTSTATUS vendor_class_request(libusb_device_t *dev,
+ int type, int recipient,
+ int request, int value, int index,
+ void *buffer, int size, int direction,
+ int *ret, int timeout);
+
+NTSTATUS abort_endpoint(libusb_device_t *dev, int endpoint, int timeout);
+NTSTATUS reset_endpoint(libusb_device_t *dev, int endpoint, int timeout);
+NTSTATUS reset_device(libusb_device_t *dev, int timeout);
+
+NTSTATUS claim_interface(libusb_device_t *dev, int interface);
+NTSTATUS release_interface(libusb_device_t *dev, int interface);
+NTSTATUS release_all_interfaces(libusb_device_t *dev);
+
+
+bool_t reg_get_hardware_id(DEVICE_OBJECT *physical_device_object,
+ char *data, int size);
+bool_t reg_get_properties(libusb_device_t *dev);
+
+
+void power_set_device_state(libusb_device_t *dev,
+ DEVICE_POWER_STATE device_state, bool_t block);
+
+USB_INTERFACE_DESCRIPTOR *
+find_interface_desc(USB_CONFIGURATION_DESCRIPTOR *config_desc,
+ unsigned int size, int interface_number, int altsetting);
+
+
+
+#endif
diff --git a/libusb/os/driver/libusb_driver_rc.rc b/libusb/os/driver/libusb_driver_rc.rc
new file mode 100644
index 0000000..d2d125c
--- /dev/null
+++ b/libusb/os/driver/libusb_driver_rc.rc
@@ -0,0 +1,25 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define RC_FILE_TYPE VFT_DRV
+#define RC_FILE_SUB_TYPE VFT2_DRV_SYSTEM
+#define RC_PRODUCT_STR "LibUSB-Win32 - Kernel Driver"
+#define RC_FILE_NAME_STR "libusb0.sys"
+
+#include "common.rc"
+
diff --git a/libusb/os/driver/makefile b/libusb/os/driver/makefile
new file mode 100644
index 0000000..5acbbd2
--- /dev/null
+++ b/libusb/os/driver/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/libusb/os/driver/pnp.c b/libusb/os/driver/pnp.c
new file mode 100644
index 0000000..fb0abdc
--- /dev/null
+++ b/libusb/os/driver/pnp.c
@@ -0,0 +1,216 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+static NTSTATUS DDKAPI
+on_start_complete(DEVICE_OBJECT *device_object, IRP *irp,
+ void *context);
+
+static NTSTATUS DDKAPI
+on_device_usage_notification_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context);
+
+static NTSTATUS DDKAPI
+on_query_capabilities_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context);
+
+
+NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ UNICODE_STRING symbolic_link_name;
+ WCHAR tmp_name[128];
+
+ status = remove_lock_acquire(dev);
+
+ if(!NT_SUCCESS(status))
+ {
+ return complete_irp(irp, status, 0);
+ }
+
+ DEBUG_PRINT_NL();
+
+ switch(stack_location->MinorFunction)
+ {
+ case IRP_MN_REMOVE_DEVICE:
+
+ DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_REMOVE_DEVICE");
+
+ dev->is_started = FALSE;
+
+ /* wait until all outstanding requests are finished */
+ remove_lock_release_and_wait(dev);
+
+ status = pass_irp_down(dev, irp, NULL, NULL);
+
+ DEBUG_MESSAGE("dispatch_pnp(): deleting device #%d", dev->id);
+
+ _snwprintf(tmp_name, sizeof(tmp_name)/sizeof(WCHAR), L"%s%04d",
+ LIBUSB0_SYMBOLIC_LINK_NAME, dev->id);
+
+ /* delete the symbolic link */
+ RtlInitUnicodeString(&symbolic_link_name, tmp_name);
+ IoDeleteSymbolicLink(&symbolic_link_name);
+
+ /* delete the device object */
+ IoDetachDevice(dev->next_stack_device);
+ IoDeleteDevice(dev->self);
+
+ return status;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+
+ DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_SURPRISE_REMOVAL");
+ dev->is_started = FALSE;
+ break;
+
+ case IRP_MN_START_DEVICE:
+
+ DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_START_DEVICE");
+
+ if(!NT_SUCCESS(set_configuration(dev, 1, 1000)))
+ {
+ DEBUG_ERROR("dispatch_pnp(): IRP_MN_START_DEVICE: selecting "
+ "configuration failed");
+ }
+
+ /* report device state to Power Manager */
+ /* power_state.DeviceState has been set to D0 by add_device() */
+ PoSetPowerState(dev->self, DevicePowerState, dev->power_state);
+
+ return pass_irp_down(dev, irp, on_start_complete, NULL);
+
+ case IRP_MN_STOP_DEVICE:
+
+ dev->is_started = FALSE;
+ DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_STOP_DEVICE");
+ break;
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+
+ DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_DEVICE_USAGE_NOTIFICATION");
+
+ if(!dev->self->AttachedDevice
+ || (dev->self->AttachedDevice->Flags & DO_POWER_PAGABLE))
+ {
+ dev->self->Flags |= DO_POWER_PAGABLE;
+ }
+
+ return pass_irp_down(dev, irp, on_device_usage_notification_complete,
+ NULL);
+
+ case IRP_MN_QUERY_CAPABILITIES:
+
+ DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_QUERY_CAPABILITIES");
+
+ if(!dev->is_filter)
+ {
+ /* apply registry setting */
+ stack_location->Parameters.DeviceCapabilities.Capabilities
+ ->SurpriseRemovalOK = dev->surprise_removal_ok;
+ }
+
+ return pass_irp_down(dev, irp, on_query_capabilities_complete, NULL);
+
+ default:
+ ;
+ }
+
+ remove_lock_release(dev);
+ return pass_irp_down(dev, irp, NULL, NULL);
+}
+
+static NTSTATUS DDKAPI
+on_start_complete(DEVICE_OBJECT *device_object, IRP *irp, void *context)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ if(irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if(dev->next_stack_device->Characteristics & FILE_REMOVABLE_MEDIA)
+ {
+ device_object->Characteristics |= FILE_REMOVABLE_MEDIA;
+ }
+
+ dev->is_started = TRUE;
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS DDKAPI
+on_device_usage_notification_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ if(irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if(!(dev->next_stack_device->Flags & DO_POWER_PAGABLE))
+ {
+ device_object->Flags &= ~DO_POWER_PAGABLE;
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS DDKAPI
+on_query_capabilities_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+
+ if(irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if(NT_SUCCESS(irp->IoStatus.Status))
+ {
+ if(!dev->is_filter)
+ {
+ /* apply registry setting */
+ stack_location->Parameters.DeviceCapabilities.Capabilities
+ ->SurpriseRemovalOK = dev->surprise_removal_ok;
+ }
+
+ /* save supported device power states */
+ memcpy(dev->device_power_states, stack_location
+ ->Parameters.DeviceCapabilities.Capabilities->DeviceState,
+ sizeof(dev->device_power_states));
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
diff --git a/libusb/os/driver/power.c b/libusb/os/driver/power.c
new file mode 100644
index 0000000..38cc1f6
--- /dev/null
+++ b/libusb/os/driver/power.c
@@ -0,0 +1,205 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+static NTSTATUS DDKAPI
+on_power_state_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context);
+
+static void DDKAPI
+on_power_set_device_state_complete(DEVICE_OBJECT *device_object,
+ UCHAR minor_function,
+ POWER_STATE power_state,
+ void *context,
+ IO_STATUS_BLOCK *io_status);
+
+NTSTATUS dispatch_power(libusb_device_t *dev, IRP *irp)
+{
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ POWER_STATE power_state;
+ NTSTATUS status;
+
+ status = remove_lock_acquire(dev);;
+
+ if(!NT_SUCCESS(status))
+ {
+ irp->IoStatus.Status = status;
+ PoStartNextPowerIrp(irp);
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ return status;
+ }
+
+ if(stack_location->MinorFunction == IRP_MN_SET_POWER)
+ {
+ power_state = stack_location->Parameters.Power.State;
+
+ if(stack_location->Parameters.Power.Type == SystemPowerState)
+ {
+ DEBUG_MESSAGE("dispatch_power(): IRP_MN_SET_POWER: S%d",
+ power_state.SystemState - PowerSystemWorking);
+ }
+ else
+ {
+ DEBUG_MESSAGE("dispatch_power(): IRP_MN_SET_POWER: D%d",
+ power_state.DeviceState - PowerDeviceD0);
+
+ if(power_state.DeviceState > dev->power_state.DeviceState)
+ {
+ /* device is powered down, report device state to the */
+ /* Power Manager before sending the IRP down */
+ /* (power up is handled by the completion routine) */
+ PoSetPowerState(dev->self, DevicePowerState, power_state);
+ }
+ }
+
+ /* TODO: should PoStartNextPowerIrp() be called here or from the */
+ /* completion routine? */
+ PoStartNextPowerIrp(irp);
+
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ IoSetCompletionRoutine(irp,
+ on_power_state_complete,
+ dev,
+ TRUE, /* on success */
+ TRUE, /* on error */
+ TRUE);/* on cancel */
+
+ return PoCallDriver(dev->next_stack_device, irp);
+ }
+ else
+ {
+ /* pass all other power IRPs down without setting a completion routine */
+ PoStartNextPowerIrp(irp);
+ IoSkipCurrentIrpStackLocation(irp);
+ status = PoCallDriver(dev->next_stack_device, irp);
+ remove_lock_release(dev);
+
+ return status;
+ }
+}
+
+
+static NTSTATUS DDKAPI
+on_power_state_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context)
+{
+ libusb_device_t *dev = context;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ POWER_STATE power_state = stack_location->Parameters.Power.State;
+ DEVICE_POWER_STATE dev_power_state;
+
+ if(irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if(NT_SUCCESS(irp->IoStatus.Status))
+ {
+ if(stack_location->Parameters.Power.Type == SystemPowerState)
+ {
+ DEBUG_MESSAGE("on_power_state_complete(): S%d",
+ power_state.SystemState - PowerSystemWorking);
+
+ /* save current system state */
+ dev->power_state.SystemState = power_state.SystemState;
+
+ /* set device power status correctly */
+ /* dev_power_state = power_state.SystemState == PowerSystemWorking ? */
+ /* PowerDeviceD0 : PowerDeviceD3; */
+
+ /* get supported device power state from the array reported by */
+ /* IRP_MN_QUERY_CAPABILITIES */
+ dev_power_state = dev->device_power_states[power_state.SystemState];
+
+ /* set the device power state, but don't block the thread */
+ power_set_device_state(dev, dev_power_state, FALSE);
+ }
+ else /* DevicePowerState */
+ {
+ DEBUG_MESSAGE("on_power_state_complete(): D%d",
+ power_state.DeviceState - PowerDeviceD0);
+
+ if(power_state.DeviceState <= dev->power_state.DeviceState)
+ {
+ /* device is powered up, */
+ /* report device state to Power Manager */
+ PoSetPowerState(dev->self, DevicePowerState, power_state);
+ }
+
+ /* save current device state */
+ dev->power_state.DeviceState = power_state.DeviceState;
+ }
+ }
+ else
+ {
+ DEBUG_MESSAGE("on_power_state_complete(): failed");
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+
+static void DDKAPI
+on_power_set_device_state_complete(DEVICE_OBJECT *device_object,
+ UCHAR minor_function,
+ POWER_STATE power_state,
+ void *context,
+ IO_STATUS_BLOCK *io_status)
+{
+ KeSetEvent((KEVENT *)context, EVENT_INCREMENT, FALSE);
+}
+
+
+void power_set_device_state(libusb_device_t *dev,
+ DEVICE_POWER_STATE device_state, bool_t block)
+{
+ NTSTATUS status;
+ KEVENT event;
+ POWER_STATE power_state;
+
+ power_state.DeviceState = device_state;
+
+ if(block) /* wait for IRP to complete */
+ {
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ /* set the device power state and wait for completion */
+ status = PoRequestPowerIrp(dev->physical_device_object,
+ IRP_MN_SET_POWER,
+ power_state,
+ on_power_set_device_state_complete,
+ &event, NULL);
+
+ if(status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ }
+ }
+ else
+ {
+ PoRequestPowerIrp(dev->physical_device_object, IRP_MN_SET_POWER,
+ power_state, NULL, NULL, NULL);
+ }
+}
diff --git a/libusb/os/driver/release_interface.c b/libusb/os/driver/release_interface.c
new file mode 100644
index 0000000..0b8987b
--- /dev/null
+++ b/libusb/os/driver/release_interface.c
@@ -0,0 +1,69 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS release_interface(libusb_device_t *dev, int interface)
+{
+ DEBUG_MESSAGE("release_interface(): interface %d", interface);
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("release_interface(): device is not configured");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if(interface >= LIBUSB0_MAX_NUMBER_OF_INTERFACES)
+ {
+ DEBUG_ERROR("release_interface(): interface number %d too high",
+ interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if(!dev->config.interfaces[interface].valid)
+ {
+ DEBUG_ERROR("release_interface(): invalid interface %02d", interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if(!dev->config.interfaces[interface].claimed)
+ {
+ DEBUG_ERROR("claim_interface(): could not release interface %d, "
+ "interface is not claimed", interface);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ dev->config.interfaces[interface].claimed = FALSE;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS release_all_interfaces(libusb_device_t *dev)
+{
+ int i;
+
+ for(i = 0; i < LIBUSB0_MAX_NUMBER_OF_INTERFACES; i++)
+ {
+ dev->config.interfaces[i].claimed = FALSE;
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/libusb/os/driver/reset_device.c b/libusb/os/driver/reset_device.c
new file mode 100644
index 0000000..188408d
--- /dev/null
+++ b/libusb/os/driver/reset_device.c
@@ -0,0 +1,46 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS reset_device(libusb_device_t *dev, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DEBUG_MESSAGE("reset_device()");
+
+ status = call_usbd(dev, NULL, IOCTL_INTERNAL_USB_RESET_PORT, timeout);
+
+ if(!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("reset_device(): IOCTL_INTERNAL_USB_RESET_PORT failed: "
+ "status: 0x%x", status);
+ }
+
+ status = call_usbd(dev, NULL, IOCTL_INTERNAL_USB_CYCLE_PORT, timeout);
+
+ if(!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("reset_device(): IOCTL_INTERNAL_USB_CYCLE_PORT failed: "
+ "status: 0x%x", status);
+ }
+
+ return status;
+}
diff --git a/libusb/os/driver/reset_endpoint.c b/libusb/os/driver/reset_endpoint.c
new file mode 100644
index 0000000..bb83c15
--- /dev/null
+++ b/libusb/os/driver/reset_endpoint.c
@@ -0,0 +1,59 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS reset_endpoint(libusb_device_t *dev, int endpoint, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("reset_endpoint(): endpoint 0x%02x", endpoint);
+ DEBUG_MESSAGE("reset_endpoint(): timeout %d", timeout);
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("reset_endpoint(): invalid configuration 0");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ memset(&urb, 0, sizeof(struct _URB_PIPE_REQUEST));
+
+ urb.UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
+ urb.UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
+
+ if(!get_pipe_handle(dev, endpoint, &urb.UrbPipeRequest.PipeHandle))
+ {
+ DEBUG_ERROR("reset_endpoint(): getting endpoint pipe failed");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("reset_endpoint(): request failed: status: 0x%x, "
+ "urb-status: 0x%x", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/libusb/os/driver/set_configuration.c b/libusb/os/driver/set_configuration.c
new file mode 100644
index 0000000..e9fc7f7
--- /dev/null
+++ b/libusb/os/driver/set_configuration.c
@@ -0,0 +1,170 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS set_configuration(libusb_device_t *dev, int configuration,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb, *urb_ptr = NULL;
+ USB_CONFIGURATION_DESCRIPTOR *configuration_descriptor = NULL;
+ USB_INTERFACE_DESCRIPTOR *interface_descriptor = NULL;
+ USBD_INTERFACE_LIST_ENTRY *interfaces = NULL;
+ int i, j, interface_number, desc_size;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("set_configuration(): configuration %d", configuration);
+ DEBUG_MESSAGE("set_configuration(): timeout %d", timeout);
+
+ if(dev->config.value == configuration)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ memset(&urb, 0, sizeof(URB));
+
+ if(!configuration)
+ {
+ urb.UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION;
+ urb.UrbHeader.Length = sizeof(struct _URB_SELECT_CONFIGURATION);
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("set_configuration(): setting configuration %d failed: "
+ "status: 0x%x, urb-status: 0x%x",
+ configuration, status, urb.UrbHeader.Status);
+ return status;
+ }
+
+ dev->config.handle = urb.UrbSelectConfiguration.ConfigurationHandle;
+ dev->config.value = 0;
+
+ clear_pipe_info(dev);
+
+ return status;
+ }
+
+ configuration_descriptor = get_config_descriptor(dev, configuration,
+ &desc_size);
+ if(!configuration_descriptor)
+ {
+ DEBUG_ERROR("set_configuration(): getting configuration descriptor "
+ "failed");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ interfaces =
+ ExAllocatePool(NonPagedPool,(configuration_descriptor->bNumInterfaces + 1)
+ * sizeof(USBD_INTERFACE_LIST_ENTRY));
+
+ if(!interfaces)
+ {
+ DEBUG_ERROR("set_configuration(): memory allocation failed");
+ ExFreePool(configuration_descriptor);
+ return STATUS_NO_MEMORY;
+ }
+
+ memset(interfaces, 0, (configuration_descriptor->bNumInterfaces + 1)
+ * sizeof(USBD_INTERFACE_LIST_ENTRY));
+
+ interface_number = 0;
+
+ for(i = 0; i < configuration_descriptor->bNumInterfaces; i++)
+ {
+ for(j = interface_number; j < LIBUSB0_MAX_NUMBER_OF_INTERFACES; j++)
+ {
+ interface_descriptor =
+ find_interface_desc(configuration_descriptor, desc_size, j, 0);
+ if(interface_descriptor)
+ {
+ interface_number = ++j;
+ break;
+ }
+ }
+
+ if(!interface_descriptor)
+ {
+ DEBUG_ERROR("set_configuration(): unable to find interface "
+ "descriptor at index %d", i);
+ ExFreePool(interfaces);
+ ExFreePool(configuration_descriptor);
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ DEBUG_MESSAGE("set_configuration(): found interface %d",
+ interface_descriptor->bInterfaceNumber);
+ interfaces[i].InterfaceDescriptor = interface_descriptor;
+ }
+ }
+
+ urb_ptr = USBD_CreateConfigurationRequestEx(configuration_descriptor,
+ interfaces);
+
+ if(!urb_ptr)
+ {
+ DEBUG_ERROR("set_configuration(): memory allocation failed");
+ ExFreePool(interfaces);
+ ExFreePool(configuration_descriptor);
+ return STATUS_NO_MEMORY;
+ }
+
+ for(i = 0; i < configuration_descriptor->bNumInterfaces; i++)
+ {
+ for(j = 0; j < (int)interfaces[i].Interface->NumberOfPipes; j++)
+ {
+ interfaces[i].Interface->Pipes[j].MaximumTransferSize
+ = LIBUSB0_MAX_READ_WRITE;
+ }
+ }
+
+ status = call_usbd(dev, urb_ptr, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb_ptr->UrbHeader.Status))
+ {
+ DEBUG_ERROR("set_configuration(): setting configuration %d failed: "
+ "status: 0x%x, urb-status: 0x%x",
+ configuration, status, urb_ptr->UrbHeader.Status);
+ ExFreePool(interfaces);
+ ExFreePool(configuration_descriptor);
+ ExFreePool(urb_ptr);
+ return status;
+ }
+
+ dev->config.handle = urb_ptr->UrbSelectConfiguration.ConfigurationHandle;
+ dev->config.value = configuration;
+
+ clear_pipe_info(dev);
+
+ for(i = 0; i < configuration_descriptor->bNumInterfaces; i++)
+ {
+ update_pipe_info(dev, interfaces[i].Interface);
+ }
+
+ ExFreePool(interfaces);
+ ExFreePool(urb_ptr);
+ ExFreePool(configuration_descriptor);
+
+ return status;
+}
diff --git a/libusb/os/driver/set_descriptor.c b/libusb/os/driver/set_descriptor.c
new file mode 100644
index 0000000..70553f6
--- /dev/null
+++ b/libusb/os/driver/set_descriptor.c
@@ -0,0 +1,77 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS set_descriptor(libusb_device_t *dev,
+ void *buffer, int size, int type, int recipient,
+ int index, int language_id, int *sent, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("set_descriptor(): buffer size %d", size);
+ DEBUG_MESSAGE("set_descriptor(): type %04d", type);
+ DEBUG_MESSAGE("set_descriptor(): recipient %04d", recipient);
+ DEBUG_MESSAGE("set_descriptor(): index %04d", index);
+ DEBUG_MESSAGE("set_descriptor(): language id %04d", language_id);
+ DEBUG_MESSAGE("set_descriptor(): timeout %d", timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT;
+ break;
+ default:
+ DEBUG_ERROR("set_descriptor(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+ urb.UrbControlDescriptorRequest.TransferBufferLength = size;
+ urb.UrbControlDescriptorRequest.TransferBuffer = buffer;
+ urb.UrbControlDescriptorRequest.DescriptorType = (UCHAR)type;
+ urb.UrbControlDescriptorRequest.Index = (UCHAR)index;
+ urb.UrbControlDescriptorRequest.LanguageId = (USHORT)language_id;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("set_descriptor(): setting descriptor failed: status: "
+ "0x%x, urb-status: 0x%x", status, urb.UrbHeader.Status);
+ }
+ else
+ {
+ *sent = urb.UrbControlDescriptorRequest.TransferBufferLength;
+ }
+ return status;
+}
diff --git a/libusb/os/driver/set_feature.c b/libusb/os/driver/set_feature.c
new file mode 100644
index 0000000..8b06a02
--- /dev/null
+++ b/libusb/os/driver/set_feature.c
@@ -0,0 +1,71 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS set_feature(libusb_device_t *dev, int recipient, int index,
+ int feature, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("set_feature(): recipient %02d", recipient);
+ DEBUG_MESSAGE("set_feature(): index %04d", index);
+ DEBUG_MESSAGE("set_feature(): feature %04d", feature);
+ DEBUG_MESSAGE("set_feature(): timeout %d", timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
+
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_OTHER;
+ urb.UrbControlFeatureRequest.Index = 0;
+ break;
+ default:
+ DEBUG_ERROR("set_feature(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_FEATURE_REQUEST);
+ urb.UrbControlFeatureRequest.FeatureSelector = (USHORT)feature;
+ urb.UrbControlFeatureRequest.Index = (USHORT)index;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("set_feature(): setting feature failed: status: 0x%x, "
+ "urb-status: 0x%x", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/libusb/os/driver/set_interface.c b/libusb/os/driver/set_interface.c
new file mode 100644
index 0000000..d7732f6
--- /dev/null
+++ b/libusb/os/driver/set_interface.c
@@ -0,0 +1,123 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS set_interface(libusb_device_t *dev, int interface, int altsetting,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB *urb;
+ int i, config_size, tmp_size;
+
+ USB_CONFIGURATION_DESCRIPTOR *configuration_descriptor = NULL;
+ USB_INTERFACE_DESCRIPTOR *interface_descriptor = NULL;
+ USBD_INTERFACE_INFORMATION *interface_information = NULL;
+
+ DEBUG_PRINT_NL();
+ DEBUG_MESSAGE("set_interface(): interface %d", interface);
+ DEBUG_MESSAGE("set_interface(): altsetting %d", altsetting);
+ DEBUG_MESSAGE("set_interface(): timeout %d", timeout);
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("release_interface(): device is not configured");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ configuration_descriptor = get_config_descriptor(dev, dev->config.value,
+ &config_size);
+ if(!configuration_descriptor)
+ {
+ DEBUG_ERROR("set_interface(): memory_allocation error");
+ return STATUS_NO_MEMORY;
+ }
+
+ interface_descriptor =
+ find_interface_desc(configuration_descriptor, config_size,
+ interface, altsetting);
+
+ if(!interface_descriptor)
+ {
+ DEBUG_ERROR("set_interface(): interface %d or altsetting %d invalid",
+ interface, altsetting);
+ ExFreePool(configuration_descriptor);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ tmp_size = sizeof(struct _URB_SELECT_INTERFACE)
+ + interface_descriptor->bNumEndpoints
+ * sizeof(USBD_PIPE_INFORMATION);
+
+
+ urb = ExAllocatePool(NonPagedPool, tmp_size);
+
+ if(!urb)
+ {
+ DEBUG_ERROR("set_interface(): memory_allocation error");
+ ExFreePool(configuration_descriptor);
+ return STATUS_NO_MEMORY;
+ }
+
+ memset(urb, 0, tmp_size);
+
+ urb->UrbHeader.Function = URB_FUNCTION_SELECT_INTERFACE;
+ urb->UrbHeader.Length = (USHORT)tmp_size;
+
+ urb->UrbSelectInterface.ConfigurationHandle = dev->config.handle;
+ urb->UrbSelectInterface.Interface.Length =
+ sizeof(struct _USBD_INTERFACE_INFORMATION);
+ urb->UrbSelectInterface.Interface.NumberOfPipes =
+ interface_descriptor->bNumEndpoints;
+ urb->UrbSelectInterface.Interface.Length +=
+ interface_descriptor->bNumEndpoints
+ * sizeof(struct _USBD_PIPE_INFORMATION);
+
+ urb->UrbSelectInterface.Interface.InterfaceNumber = (UCHAR)interface;
+ urb->UrbSelectInterface.Interface.AlternateSetting = (UCHAR)altsetting;
+
+ interface_information = &urb->UrbSelectInterface.Interface;
+
+ for(i = 0; i < interface_descriptor->bNumEndpoints; i++)
+ {
+ interface_information->Pipes[i].MaximumTransferSize
+ = LIBUSB0_MAX_READ_WRITE;
+ }
+
+ status = call_usbd(dev, urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb->UrbHeader.Status))
+ {
+ DEBUG_ERROR("set_interface(): setting interface failed: status: 0x%x, "
+ "urb-status: 0x%x", status, urb->UrbHeader.Status);
+ ExFreePool(configuration_descriptor);
+ ExFreePool(urb);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ update_pipe_info(dev, interface_information);
+
+ ExFreePool(configuration_descriptor);
+ ExFreePool(urb);
+
+ return status;
+}
+
diff --git a/libusb/os/driver/sources b/libusb/os/driver/sources
new file mode 100644
index 0000000..7b247b1
--- /dev/null
+++ b/libusb/os/driver/sources
@@ -0,0 +1,33 @@
+TARGETNAME = libusb0
+TARGETPATH = obj
+TARGETTYPE = DRIVER
+USER_C_FLAGS = /O2
+TARGETLIBS = $(DDK_LIB_PATH)\usbd.lib
+C_DEFINES = /DVERSION_MAJOR=0 /DVERSION_MINOR=1 /DVERSION_MICRO=12 \
+ /DVERSION_NANO=1 /DRC_VERSION=0,1,12,1 \
+ /DRC_VERSION_STR="\"0.1.12.1\""
+
+SOURCES = abort_endpoint.c \
+claim_interface.c \
+clear_feature.c \
+dispatch.c \
+driver_registry.c \
+get_configuration.c \
+get_descriptor.c \
+get_interface.c \
+get_status.c \
+ioctl.c \
+libusb_driver.c \
+pnp.c \
+power.c \
+release_interface.c \
+reset_device.c \
+reset_endpoint.c \
+set_configuration.c \
+set_descriptor.c \
+set_feature.c \
+set_interface.c \
+transfer.c \
+vendor_request.c \
+driver_debug.c \
+libusb_driver_rc.rc
diff --git a/libusb/os/driver/temp b/libusb/os/driver/temp
new file mode 100644
index 0000000..6776819
--- /dev/null
+++ b/libusb/os/driver/temp
@@ -0,0 +1,13 @@
+claim_interface.c
+driver_debug.c
+driver_debug.h
+driver_registry.c
+get_descriptor.c
+ioctl.c
+libusb_driver.c
+libusb_driver.h
+pnp.bak.c
+pnp.c
+release_interface.c
+set_configuration.c
+set_interface.c
diff --git a/libusb/os/driver/transfer.c b/libusb/os/driver/transfer.c
new file mode 100644
index 0000000..c7401e9
--- /dev/null
+++ b/libusb/os/driver/transfer.c
@@ -0,0 +1,238 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+typedef struct {
+ URB *urb;
+ int sequence;
+} context_t;
+
+static int sequence = 0;
+
+NTSTATUS DDKAPI transfer_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context);
+
+static NTSTATUS create_urb(libusb_device_t *dev, URB **urb, int direction,
+ int urb_function, int endpoint, int packet_size,
+ MDL *buffer, int size);
+
+NTSTATUS transfer(libusb_device_t *dev, IRP *irp,
+ int direction, int urb_function, int endpoint,
+ int packet_size, MDL *buffer, int size)
+{
+ IO_STACK_LOCATION *stack_location = NULL;
+ context_t *context;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DEBUG_PRINT_NL();
+
+ if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
+ DEBUG_MESSAGE("transfer(): isochronous transfer");
+ else
+ DEBUG_MESSAGE("transfer(): bulk or interrupt transfer");
+
+ if(direction == USBD_TRANSFER_DIRECTION_IN)
+ DEBUG_MESSAGE("transfer(): direction in");
+ else
+ DEBUG_MESSAGE("transfer(): direction out");
+
+ DEBUG_MESSAGE("transfer(): endpoint 0x%02x", endpoint);
+
+ if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
+ DEBUG_MESSAGE("transfer(): packet_size 0x%x", packet_size);
+
+ DEBUG_MESSAGE("transfer(): size %d", size);
+ DEBUG_MESSAGE("transfer(): sequence %d", sequence);
+ DEBUG_PRINT_NL();
+
+ if(!dev->config.value)
+ {
+ DEBUG_ERROR("transfer(): invalid configuration 0");
+ remove_lock_release(dev);
+ return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ context = ExAllocatePool(NonPagedPool, sizeof(context_t));
+
+ if(!context)
+ {
+ remove_lock_release(dev);
+ return complete_irp(irp, STATUS_NO_MEMORY, 0);
+ }
+
+ status = create_urb(dev, &context->urb, direction, urb_function,
+ endpoint, packet_size, buffer, size);
+
+ if(!NT_SUCCESS(status))
+ {
+ ExFreePool(context);
+ remove_lock_release(dev);
+ return complete_irp(irp, status, 0);
+ }
+
+ context->sequence = sequence++;
+
+ stack_location = IoGetNextIrpStackLocation(irp);
+
+ stack_location->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ stack_location->Parameters.Others.Argument1 = context->urb;
+ stack_location->Parameters.DeviceIoControl.IoControlCode
+ = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(irp, transfer_complete, context,
+ TRUE, TRUE, TRUE);
+
+ return IoCallDriver(dev->target_device, irp);
+}
+
+
+NTSTATUS DDKAPI transfer_complete(DEVICE_OBJECT *device_object, IRP *irp,
+ void *context)
+{
+ context_t *c = (context_t *)context;
+ int transmitted = 0;
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ if(irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if(NT_SUCCESS(irp->IoStatus.Status)
+ && USBD_SUCCESS(c->urb->UrbHeader.Status))
+ {
+ if(c->urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ transmitted = c->urb->UrbIsochronousTransfer.TransferBufferLength;
+ }
+ if(c->urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER)
+ {
+ transmitted
+ = c->urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+ }
+
+ DEBUG_MESSAGE("transfer_complete(): sequence %d: %d bytes transmitted",
+ c->sequence, transmitted);
+ }
+ else
+ {
+ if(irp->IoStatus.Status == STATUS_CANCELLED)
+ {
+ DEBUG_ERROR("transfer_complete(): sequence %d: timeout error",
+ c->sequence);
+ }
+ else
+ {
+ DEBUG_ERROR("transfer_complete(): sequence %d: transfer failed: "
+ "status: 0x%x, urb-status: 0x%x",
+ c->sequence, irp->IoStatus.Status,
+ c->urb->UrbHeader.Status);
+ }
+ }
+
+ ExFreePool(c->urb);
+ ExFreePool(c);
+
+ irp->IoStatus.Information = transmitted;
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS create_urb(libusb_device_t *dev, URB **urb, int direction,
+ int urb_function, int endpoint, int packet_size,
+ MDL *buffer, int size)
+{
+ USBD_PIPE_HANDLE pipe_handle = NULL;
+ int num_packets = 0;
+ int i, urb_size;
+
+ *urb = NULL;
+
+ if(!get_pipe_handle(dev, endpoint, &pipe_handle))
+ {
+ DEBUG_ERROR("create_urb(): getting endpoint pipe failed");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* isochronous transfer */
+ if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ num_packets = (size + packet_size - 1) / packet_size;
+
+ if(num_packets > 255)
+ {
+ DEBUG_ERROR("create_urb(): transfer size too large");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb_size = sizeof(struct _URB_ISOCH_TRANSFER)
+ + sizeof(USBD_ISO_PACKET_DESCRIPTOR) * num_packets;
+ }
+ else /* bulk or interrupt transfer */
+ {
+ urb_size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
+ }
+
+ *urb = ExAllocatePool(NonPagedPool, urb_size);
+
+ if(!*urb)
+ {
+ DEBUG_ERROR("create_urb(): memory allocation error");
+ return STATUS_NO_MEMORY;
+ }
+
+ memset(*urb, 0, urb_size);
+
+ (*urb)->UrbHeader.Length = (USHORT)urb_size;
+ (*urb)->UrbHeader.Function = (USHORT)urb_function;
+
+ /* isochronous transfer */
+ if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ (*urb)->UrbIsochronousTransfer.PipeHandle = pipe_handle;
+ (*urb)->UrbIsochronousTransfer.TransferFlags
+ = direction | USBD_SHORT_TRANSFER_OK | USBD_START_ISO_TRANSFER_ASAP;
+ (*urb)->UrbIsochronousTransfer.TransferBufferLength = size;
+ (*urb)->UrbIsochronousTransfer.TransferBufferMDL = buffer;
+ (*urb)->UrbIsochronousTransfer.NumberOfPackets = num_packets;
+
+ for(i = 0; i < num_packets; i++)
+ {
+ (*urb)->UrbIsochronousTransfer.IsoPacket[i].Offset = i * packet_size;
+ (*urb)->UrbIsochronousTransfer.IsoPacket[i].Length = packet_size;
+ }
+ }
+ /* bulk or interrupt transfer */
+ else
+ {
+ (*urb)->UrbBulkOrInterruptTransfer.PipeHandle = pipe_handle;
+ (*urb)->UrbBulkOrInterruptTransfer.TransferFlags
+ = direction | USBD_SHORT_TRANSFER_OK;
+ (*urb)->UrbBulkOrInterruptTransfer.TransferBufferLength = size;
+ (*urb)->UrbBulkOrInterruptTransfer.TransferBufferMDL = buffer;
+ }
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/libusb/os/driver/usbd.def b/libusb/os/driver/usbd.def
new file mode 100644
index 0000000..5c283bb
--- /dev/null
+++ b/libusb/os/driver/usbd.def
@@ -0,0 +1,35 @@
+
+EXPORTS
+USBD_AllocateDeviceName
+USBD_CalculateUsbBandwidth
+USBD_CompleteRequest
+USBD_CreateConfigurationRequest
+USBD_CreateConfigurationRequestEx
+USBD_CreateDevice
+USBD_Debug_GetHeap
+USBD_Debug_LogEntry
+USBD_Debug_RetHeap
+USBD_Dispatch
+USBD_FreeDeviceMutex
+USBD_FreeDeviceName
+USBD_GetDeviceInformation
+USBD_GetInterfaceLength
+USBD_GetPdoRegistryParameter
+USBD_GetSuspendPowerState
+USBD_GetUSBDIVersion
+USBD_InitializeDevice
+USBD_MakePdoName
+USBD_ParseConfigurationDescriptor
+USBD_ParseConfigurationDescriptorEx
+USBD_ParseDescriptors
+USBD_QueryBusTime
+USBD_RegisterHcDeviceCapabilities
+USBD_RegisterHcFilter
+USBD_RegisterHostController
+USBD_RemoveDevice
+USBD_RestoreDevice
+USBD_SetSuspendPowerState
+USBD_WaitDeviceMutex
+USBD_CreateConfigurationRequestEx@8=_USBD_CreateConfigurationRequestEx@8
+USBD_ParseConfigurationDescriptorEx@28=_USBD_ParseConfigurationDescriptorEx@28
+USBD_ParseDescriptors@16=_USBD_ParseDescriptors@16
diff --git a/libusb/os/driver/usbdlib_gcc.h b/libusb/os/driver/usbdlib_gcc.h
new file mode 100644
index 0000000..84d9238
--- /dev/null
+++ b/libusb/os/driver/usbdlib_gcc.h
@@ -0,0 +1,308 @@
+
+#ifndef __USBDLIB_H
+#define __USBDLIB_H
+
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma pack(push,4)
+
+
+ typedef struct _USBD_INTERFACE_LIST_ENTRY {
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ PUSBD_INTERFACE_INFORMATION Interface;
+ } USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY;
+
+
+#define URB_STATUS(urb) ((urb)->UrbHeader.Status)
+
+#define GET_SELECT_CONFIGURATION_REQUEST_SIZE(totalInterfaces, totalPipes) \
+ (sizeof(struct _URB_SELECT_CONFIGURATION) \
+ + ((totalInterfaces - 1) * sizeof(USBD_INTERFACE_INFORMATION)) \
+ + ((totalPipes - 1) * sizeof(USBD_PIPE_INFORMATION)))
+
+#define GET_SELECT_INTERFACE_REQUEST_SIZE(totalPipes) \
+ (sizeof(struct _URB_SELECT_INTERFACE) \
+ + ((totalPipes - 1) * sizeof(USBD_PIPE_INFORMATION)))
+
+#define GET_USBD_INTERFACE_SIZE(numEndpoints) \
+ (sizeof(USBD_INTERFACE_INFORMATION) \
+ + (sizeof(USBD_PIPE_INFORMATION)*(numEndpoints)) \
+ - sizeof(USBD_PIPE_INFORMATION))
+
+#define GET_ISO_URB_SIZE(n) (sizeof(struct _URB_ISOCH_TRANSFER) \
+ + sizeof(USBD_ISO_PACKET_DESCRIPTOR) * n)
+
+
+#define UsbBuildInterruptOrBulkTransferRequest(urb, \
+ length, \
+ pipeHandle, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ transferFlags, \
+ link) { \
+ (urb)->UrbHeader.Function = \
+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbBulkOrInterruptTransfer.PipeHandle = (pipeHandle); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferFlags = \
+ (transferFlags); \
+ (urb)->UrbBulkOrInterruptTransfer.UrbLink = (link); }
+
+
+#define UsbBuildGetDescriptorRequest(urb, \
+ length, \
+ descriptorType, \
+ descriptorIndex, \
+ languageId, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ link) { \
+ (urb)->UrbHeader.Function = \
+ URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbControlDescriptorRequest.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbControlDescriptorRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbControlDescriptorRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbControlDescriptorRequest.DescriptorType = \
+ (descriptorType); \
+ (urb)->UrbControlDescriptorRequest.Index = (descriptorIndex); \
+ (urb)->UrbControlDescriptorRequest.LanguageId = (languageId); \
+ (urb)->UrbControlDescriptorRequest.UrbLink = (link); }
+
+
+
+#define UsbBuildGetStatusRequest(urb, \
+ op, \
+ index, \
+ transferBuffer, \
+ transferBufferMDL, \
+ link) { \
+ (urb)->UrbHeader.Function = (op); \
+ (urb)->UrbHeader.Length = \
+ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST); \
+ (urb)->UrbControlGetStatusRequest.TransferBufferLength = \
+ sizeof(USHORT); \
+ (urb)->UrbControlGetStatusRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbControlGetStatusRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbControlGetStatusRequest.Index = (index); \
+ (urb)->UrbControlGetStatusRequest.UrbLink = (link); }
+
+
+#define UsbBuildFeatureRequest(urb, \
+ op, \
+ featureSelector, \
+ index, \
+ link) { \
+ (urb)->UrbHeader.Function = (op); \
+ (urb)->UrbHeader.Length = \
+ sizeof(struct _URB_CONTROL_FEATURE_REQUEST); \
+ (urb)->UrbControlFeatureRequest.FeatureSelector = \
+ (featureSelector); \
+ (urb)->UrbControlFeatureRequest.Index = (index); \
+ (urb)->UrbControlFeatureRequest.UrbLink = (link); }
+
+
+
+#define UsbBuildSelectConfigurationRequest(urb, \
+ length, \
+ configurationDescriptor) { \
+ (urb)->UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbSelectConfiguration.ConfigurationDescriptor = \
+ (configurationDescriptor); }
+
+#define UsbBuildSelectInterfaceRequest(urb, \
+ length, \
+ configurationHandle, \
+ interfaceNumber, \
+ alternateSetting) { \
+ (urb)->UrbHeader.Function = URB_FUNCTION_SELECT_INTERFACE; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbSelectInterface.Interface.AlternateSetting = \
+ (alternateSetting); \
+ (urb)->UrbSelectInterface.Interface.InterfaceNumber = \
+ (interfaceNumber); \
+ (urb)->UrbSelectInterface.ConfigurationHandle = \
+ (configurationHandle); }
+
+
+#define UsbBuildVendorRequest(urb, \
+ cmd, \
+ length, \
+ transferFlags, \
+ reservedbits, \
+ request, \
+ value, \
+ index, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ link) { \
+ (urb)->UrbHeader.Function = cmd; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbControlVendorClassRequest.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbControlVendorClassRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbControlVendorClassRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbControlVendorClassRequest.RequestTypeReservedBits = \
+ (reservedbits); \
+ (urb)->UrbControlVendorClassRequest.Request = (request); \
+ (urb)->UrbControlVendorClassRequest.Value = (value); \
+ (urb)->UrbControlVendorClassRequest.Index = (index); \
+ (urb)->UrbControlVendorClassRequest.TransferFlags = \
+ (transferFlags); \
+ (urb)->UrbControlVendorClassRequest.UrbLink = (link); }
+
+
+#define UsbBuildOsFeatureDescriptorRequest(urb, \
+ length, \
+ interface, \
+ index, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ link) { \
+ (urb)->UrbHeader.Function = \
+ URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbOSFeatureDescriptorRequest.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbOSFeatureDescriptorRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbOSFeatureDescriptorRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbOSFeatureDescriptorRequest.InterfaceNumber = \
+ (interface); \
+ (urb)->UrbOSFeatureDescriptorRequest.MS_FeatureDescriptorIndex = \
+ (index); \
+ (urb)->UrbOSFeatureDescriptorRequest.UrbLink = (link); }
+
+
+ VOID
+ DDKAPI
+ USBD_Debug_LogEntry(
+ IN CHAR *Name,
+ IN ULONG Info1,
+ IN ULONG Info2,
+ IN ULONG Info3
+ );
+
+ VOID
+ DDKAPI
+ USBD_GetUSBDIVersion(
+ PUSBD_VERSION_INFORMATION VersionInformation
+ );
+
+
+ PUSB_INTERFACE_DESCRIPTOR
+ DDKAPI
+ USBD_ParseConfigurationDescriptor(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN UCHAR InterfaceNumber,
+ IN UCHAR AlternateSetting
+ );
+
+ PURB
+ DDKAPI
+ USBD_CreateConfigurationRequest(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN OUT PUSHORT Siz
+ );
+
+ PUSB_COMMON_DESCRIPTOR
+ DDKAPI
+ USBD_ParseDescriptors(
+ IN PVOID DescriptorBuffer,
+ IN ULONG TotalLength,
+ IN PVOID StartPosition,
+ IN LONG DescriptorType
+ );
+
+ PUSB_INTERFACE_DESCRIPTOR
+ DDKAPI
+ USBD_ParseConfigurationDescriptorEx(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN PVOID StartPosition,
+ IN LONG InterfaceNumber,
+ IN LONG AlternateSetting,
+ IN LONG InterfaceClass,
+ IN LONG InterfaceSubClass,
+ IN LONG InterfaceProtocol
+ );
+
+ PURB
+ DDKAPI
+ USBD_CreateConfigurationRequestEx(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList
+ );
+
+ ULONG
+ DDKAPI
+ USBD_GetInterfaceLength(
+ IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
+ IN PUCHAR BufferEnd
+ );
+
+ VOID
+ DDKAPI
+ USBD_RegisterHcFilter(
+ PDEVICE_OBJECT DeviceObject,
+ PDEVICE_OBJECT FilterDeviceObject
+ );
+
+ NTSTATUS
+ DDKAPI
+ USBD_GetPdoRegistryParameter(
+ IN PDEVICE_OBJECT PhysicalDeviceObject,
+ IN OUT PVOID Parameter,
+ IN ULONG ParameterLength,
+ IN PWCHAR KeyName,
+ IN ULONG KeyNameLength
+ );
+
+ NTSTATUS
+ DDKAPI
+ USBD_QueryBusTime(
+ IN PDEVICE_OBJECT RootHubPdo,
+ IN PULONG CurrentFrame
+ );
+
+ ULONG
+ DDKAPI
+ USBD_CalculateUsbBandwidth(
+ ULONG MaxPacketSize,
+ UCHAR EndpointType,
+ BOOLEAN LowSpeed
+ );
+
+
+#pragma pack(pop)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBDLIB_H */
+
diff --git a/libusb/os/driver/vendor_request.c b/libusb/os/driver/vendor_request.c
new file mode 100644
index 0000000..74b7913
--- /dev/null
+++ b/libusb/os/driver/vendor_request.c
@@ -0,0 +1,138 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS vendor_class_request(libusb_device_t *dev,
+ int type, int recipient,
+ int request, int value, int index,
+ void *buffer, int size, int direction,
+ int *ret, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ *ret = 0;
+
+ DEBUG_PRINT_NL();
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+ switch(type)
+ {
+ case USB_TYPE_CLASS:
+ DEBUG_MESSAGE("vendor_class_request(): type: class");
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: device");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: interface");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: endpoint");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: other");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_OTHER;
+ break;
+ default:
+ DEBUG_ERROR("vendor_class_request(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+ case USB_TYPE_VENDOR:
+ DEBUG_MESSAGE("vendor_class_request(): type: vendor");
+ switch(recipient)
+ {
+ case USB_RECIP_DEVICE:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: device");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: interface");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: endpoint");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ DEBUG_MESSAGE("vendor_class_request(): recipient: other");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_OTHER;
+ break;
+ default:
+ DEBUG_ERROR("vendor_class_request(): invalid recipient");
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ DEBUG_ERROR("vendor_class_request(): invalid type");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG_MESSAGE("vendor_class_request(): request: 0x%02x", request);
+ DEBUG_MESSAGE("vendor_class_request(): value: 0x%04x", value);
+ DEBUG_MESSAGE("vendor_class_request(): index: 0x%04x", index);
+ DEBUG_MESSAGE("vendor_class_request(): size: %d", size);
+
+ if(direction == USBD_TRANSFER_DIRECTION_IN)
+ {
+ DEBUG_MESSAGE("vendor_class_request(): direction: in");
+ }
+ else
+ {
+ DEBUG_MESSAGE("vendor_class_request(): direction: out");
+ }
+
+ DEBUG_MESSAGE("vendor_class_request(): timeout: %d", timeout);
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+ urb.UrbControlVendorClassRequest.TransferFlags
+ = direction | USBD_SHORT_TRANSFER_OK ;
+ urb.UrbControlVendorClassRequest.TransferBufferLength = size;
+ urb.UrbControlVendorClassRequest.TransferBufferMDL = NULL;
+ urb.UrbControlVendorClassRequest.TransferBuffer = buffer;
+ urb.UrbControlVendorClassRequest.Request = (UCHAR)request;
+ urb.UrbControlVendorClassRequest.Value = (USHORT)value;
+ urb.UrbControlVendorClassRequest.Index = (USHORT)index;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if(!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ DEBUG_ERROR("vendor_class_request(): request failed: status: 0x%x, "
+ "urb-status: 0x%x", status, urb.UrbHeader.Status);
+ }
+ else
+ {
+ if(direction == USBD_TRANSFER_DIRECTION_IN)
+ *ret = urb.UrbControlVendorClassRequest.TransferBufferLength;
+ DEBUG_MESSAGE("vendor_class_request(): %d bytes transmitted",
+ urb.UrbControlVendorClassRequest.TransferBufferLength);
+ }
+
+ return status;
+}
+