diff options
author | Pete Batard <pbatard@gmail.com> | 2010-03-10 13:14:51 +0000 |
---|---|---|
committer | Pete Batard <pbatard@gmail.com> | 2010-03-10 13:14:51 +0000 |
commit | fae9c17bd2405813d44186c94367d6e66d3994e6 (patch) | |
tree | 8e795a9400182bdabb61229a3791f060af1d5335 /libusb/os/driver | |
parent | 4ee3179ae1e0adefc6c5d19c036c297856ebdef9 (diff) | |
download | libusb-fae9c17bd2405813d44186c94367d6e66d3994e6.tar.gz |
libusb0.sys backend integration - part 2 (Graeme Gill)c190
Diffstat (limited to 'libusb/os/driver')
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; +} + |